package com.cci.kangdao.service.impl;

import com.alibaba.fastjson.JSON;
import com.cci.kangdao.aop.UserThreadLocal;
import com.cci.kangdao.common.type.OverTimeType;
import com.cci.kangdao.crmapi.CRMApiUtils;
import com.cci.kangdao.crmapi.CRMResponeEntity;
import com.cci.kangdao.crmapi.CRMServiceConst;
import com.cci.kangdao.dao.*;
import com.cci.kangdao.dao.model.*;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.*;
import com.cci.kangdao.task.AsyncTask;
import com.cci.kangdao.utilTool.*;
import com.cci.kangdao.wechatOrder.service.IOrderPushMessageService;
import net.sf.json.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;

/**
 * 技师处理工单类
 * 
 * @author zhangzhuang
 *
 */
@Service("TechDealWithWorkOrderService")
public class TechDealWithWorkOrderServiceImpl implements TechDealWithWorkOrderService {

	private Logger log = Logger.getLogger(this.getClass().getName());

	@Resource
	private TechDealWithWorkOrderDao techDealWithWorkOrderDao;

	@Resource
	private LoginDao loginDao;

	@Autowired
	private ConfirmationByServiceManagerDao confirmationByServiceManagerDao;

	@Resource
	private WorkOrderRepairDao workOrderRepairDao;

	@Resource
	private CRMPlatformServiceDao platformServiceDao;

	@Autowired
	private ServiceManagerAffirmDao serviceManagerAffirmDao;

	@Autowired
	private UserTDao userTDao;

	@Autowired
	private WorkOrderTDao workOrderTDao;

	@Autowired
	private PositionUserTDao positionUserTDao;

	@Autowired
	private WorkOrderPrincipalTDao workOrderPrincipalTDao;

	@Autowired
	private CompanyTDao companyTDao;

	@Autowired
	private RedisClientUtils redisClientUtils;

	@Resource
	private NoticeService noticeService;
	@Resource
	private WorkOrderFlowTDao workOrderFlowTDao;

	@Resource
	private ServiceStationDao serviceStationDao;

	@Resource
	private WorkOrderTrackTDao workOrderTrackTDao;

	@Resource
	private PropertiesUtils propertiesUtils;
	@Resource
	private IOrderPushMessageService iOrderPushMessageService;

	/*
	 * 异步任务统一处理
	 */
	@Resource
	private AsyncTask asyncTask;

	// 存放企业信息（猎鹰中创建的服务）
	public static Map<String, Object> golden_company = new HashMap<String, Object>();
	// map 存放企业与服务站的关系，在猎鹰里相当于 service 与 terminal的关系
	// key:companyId_serviceId value:sid_tid
	public static Map<String, Object> company_service = new HashMap<String, Object>();
	// map 存放服务站与轨迹的关系，在猎鹰里相当于 terminal 与 trace 的关系
	// key:serviceId_orderId_orderNo value:tid_trid
	public static Map<String, Object> trace_service = new HashMap<String, Object>();

	private String tecSetOutBody = "您的工单服务技师已出发，工单号***，";
	private String tecSetOutTitle = "技师状态更新提醒";
	private String tecSetOutTransMsg = "您的工单服务技师已出发，工单号***，";

	private String tecFunction = "5";
	private String tecCategory = "1";

	private static final Integer BATCH_LIMIT = 100;

	@Resource
	private TrackService trackService;

	/**
	 * 服务技师点击出发
	 * 变更工单状态——》插入工单操作记录——》同步工单状态至CRM——》插入工单负责人表——》记录出发点轨迹——》发送相关人员信息——》插入发送信息记录——》在高德创建相关轨迹信息
	 */
	@Transactional
	@Override
	public ModelAndView techSetOut(Map<String, Object> map) {
		// TODO Auto-generated method stub
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		HttpServletRequest request = (HttpServletRequest) map.get("request");
		String currentProvice = MapUtils.getString(map, "Province", "");
		String currentCity = MapUtils.getString(map, "City", "");
		try {
			JSONObject obj = new JSONObject();
			// 获取必要参数
			String orderId = MapUtils.getString(map, "orderId", "");
			String userId = MapUtils.getString(map, "userId", "");
			String locLon = MapUtils.getString(map, "locLon", "");
			String locLat = MapUtils.getString(map, "locLat", "");
			String location = MapUtils.getString(map, "location", "");
			String IMEI = MapUtils.getString(map, "IMEI", "");
			// String cusPhone = MapUtils.getString(map, "cusPhone","");
			int isPrincipal = MapUtils.getIntValue(map, "IsPrincipal", 1); // 是否是主技师(0:否 1:是) 默认是1
			if ("".equals(orderId) || "".equals(userId) || "".equals(locLon) || "".equals(locLat)) {
				ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
				return null;
			}
			// 根据用户Id获取用户信息
			String UserId = map.get("userId").toString();
			UserT ut = loginDao.getUserByid(UserId);
			if (null != ut) {
				long lUserId = ut.getId();
				map.put("userId", lUserId);
			} else {
				// 丢失必要参数
				obj.put("status", SMSEnum.type18.getIndex());
				obj.put("msg", SMSEnum.type18.getName());
				obj.put("data", "");
				// 返回客户
				ParameterTool.writeResponse(response, obj.toString());
				obj = null;
				return null;
			}
			// 查询工单信息
			List<Map<String, Object>> orderList = techDealWithWorkOrderDao.getCurrentOrderMsg(map);
			if (CollectionUtils.isEmpty(orderList)) {
				// 未查询到工单信息
				obj.put("status", SMSEnum.type20.getIndex());
				obj.put("msg", SMSEnum.type20.getName());
				obj.put("data", "");
				ParameterTool.writeResponse(response, obj.toString());
				obj = null;
				return null;
			}
			Map<String, Object> orderMap = orderList.get(0);
			long orderChannel = MapUtils.getLongValue(orderMap, "OrderChannel");
			CompanyT ccecChannelCompany = companyTDao.getCompanyInfoByCompanyNo("CCEC");
			CompanyT xcecChannelCompany = companyTDao.getCompanyInfoByCompanyNo("XCEC");

			// 2.5.0 dcec和ccec该技师下存在已出发，未到达的工单，不允许再出发别的工单
			if (orderChannel == ccecChannelCompany.getId() || orderChannel == 3) {
				if (workOrderTDao.getHasBeenSetOutCountByUserId(ut.getId(), Long.parseLong(orderId)) > 0) {
					obj.put("status", SMSEnum.type51.getIndex());
					obj.put("msg", SMSEnum.type51.getName());
					obj.put("data", "");
					// 返回客户
					ParameterTool.writeResponse(response, obj.toString());
					obj = null;
					return null;
				}
			}

			// 服务渠道编号
			String companyNo = orderMap.get("CompanyNo").toString();
			long workOrderCompanyId = MapUtils.getLongValue(orderMap, "CompanyId"); // 当前工单渠道
			WorkOrderT workOrderT = workOrderTDao.getWorkOrderTByOrderId(MapUtils.getLongValue(orderMap, "OrderId"));
			if (workOrderCompanyId == ccecChannelCompany.getId() && isPrincipal == 0) { // ccec渠道的副技师点击出发 只记录操作信息 不修改工单
				// 获取到副技师在负责人表中主键di
				Map<String, Object> workOrderPrincipalMap = workOrderPrincipalTDao
						.getWorkOrderPrincipalByUserId(MapUtils.getLongValue(orderMap, "OrderId"), ut.getId());
				if (MapUtils.isNotEmpty(workOrderPrincipalMap)) {
					String currentTime = LocalTimeUtil.getRealCurrentTime();
					Map<String, Object> saveWorkOrderTechnicianOperatorMap = new HashMap<>();
					saveWorkOrderTechnicianOperatorMap.put("OrderStatus", 10);
					saveWorkOrderTechnicianOperatorMap.put("WorkOrderPrincipalId",
							MapUtils.getLongValue(workOrderPrincipalMap, "ID"));
					saveWorkOrderTechnicianOperatorMap.put("LocLon", locLon);
					saveWorkOrderTechnicianOperatorMap.put("LocLat", locLat);
					saveWorkOrderTechnicianOperatorMap.put("Location", location);
					saveWorkOrderTechnicianOperatorMap.put("IMEI", IMEI);
					saveWorkOrderTechnicianOperatorMap.put("ReMark", "ccec副技师点击出发");
					saveWorkOrderTechnicianOperatorMap.put("Flag", 0);
					saveWorkOrderTechnicianOperatorMap.put("Creator", ut.getId());
					saveWorkOrderTechnicianOperatorMap.put("CreateTime", currentTime);
					techDealWithWorkOrderDao.saveWorkOrderTechnicianOperator(saveWorkOrderTechnicianOperatorMap);
					Map<String, Object> tbMap = new HashMap<String, Object>();
					tbMap.put("orderNo", MapUtils.getString(orderMap, "OrderNo"));
					tbMap.put("CCSSComplainerOrderNo", workOrderT.getOrderNoCrm());
					tbMap.put("CCSSOrderNo", workOrderT.getCCSSOrderNo());
					tbMap.put("billStatus", 10);
					tbMap.put("customerName", workOrderT.getCustomerName());
					tbMap.put("customerPhone", workOrderT.getCustomerPhone());
					tbMap.put("customerCompany", workOrderT.getCustomerCompanyName());
					tbMap.put("faultDesc", workOrderT.getCustomerComplaint());
					Map<String, Object> sSRepair = serviceStationDao.getSSRepairByStationIdAndCompanyId(
							workOrderT.getServiceStationId(), workOrderT.getOrderChannel());
					if (MapUtils.isNotEmpty(sSRepair)) {
						tbMap.put("stationNo", sSRepair.get("BusinessNo"));
					} else {
						tbMap.put("stationNo", "");
					}
					tbMap.put("actionTime", currentTime);
					tbMap.put("directorName", ut.getContact());
					tbMap.put("directorPhone", ut.getPhone());
					tbMap.put("assistEngineerName", ut.getContact());
					tbMap.put("engineerPhone", ut.getPhone());
					tbMap.put("positionLat", locLat);
					tbMap.put("positionLon", locLon);
					tbMap.put("location", location);
					tbMap.put("currentProvice", currentProvice);
					tbMap.put("currentCity", currentCity);
					tbMap.put("phoneIMEI", IMEI);
					log.error("用户点击出发异步调用同步工单状态至CRM");
					asyncTask.asyncOrderStatusToCrm(companyNo, platformServiceDao, redisClientUtils, tbMap);
					// 成功
					obj.put("status", 0);
					obj.put("msg", "success");
					obj.put("data", "");
					// 返回客户
					ParameterTool.writeResponse(response, obj.toString());
				}
			} else {
				// 工单所选服务站Id
				String serviceStationId = orderMap.get("ServiceStationId").toString();
				// 工单编号
				String OrderNo = orderMap.get("OrderNo").toString();
				// step1:变更工单状态（技师点击出发，工单状态变为已出发）
				// 填充服务技师到达时间
				map.put("departTime", LocalTimeUtil.getRealCurrentTime());
				map.put("OldUpdateTime", (String) map.get("updateTime"));
				// DBU渠道增加达到预估时间字段
				if (companyNo.toUpperCase().equals("CCI")) {
					// 起始点经纬度为当前经纬度
					String originLon = locLon;
					String originLat = locLat;
					// 目的地经纬度为故障点经纬度
					String destLon = MapUtils.getString(orderMap, "LocLon");
					String destLat = MapUtils.getString(orderMap, "LocLat");
					// 获取路线规划信息
					Map<String, Object> directionMap = GDRegion.direction(originLon, originLat, destLon, destLat);
					Long duration = MapUtils.getLong(directionMap, "duration", 0L);
					String estimatedTime = LocalTimeUtil.getTimeAfterSeconds(MapUtils.getString(map, "departTime"),
							duration);
					// 获取预估时间
					map.put("EstimatedTime", estimatedTime);
				}
				// 2.10.0 ccec渠道需要出发就提前计算预计，最快，最短里程
				if (companyNo.toUpperCase().equals(CRMServiceConst.CCEC)) {
					// 获取最快里程
					Map<String, Object> fastestDirectionMap = GDRegion.direction(GDRegion.DirectionType.FASTEST, locLon,
							locLat, String.valueOf(workOrderT.getLocLon()), String.valueOf(workOrderT.getLocLat()));
					Long fastestDistance = MapUtils.getLong(fastestDirectionMap, "distance", 0l);
					BigDecimal fastestDriveDistance = new BigDecimal(fastestDistance);
					BigDecimal fastestDriveDistanceBig = fastestDriveDistance.divide(BigDecimal.valueOf(1000L), 2,
							RoundingMode.DOWN);
					// 获取最短里程
					Map<String, Object> shortestDirectionMap = GDRegion.direction(locLon, locLat,
							String.valueOf(workOrderT.getLocLon()), String.valueOf(workOrderT.getLocLat()));
					Long shortestDistance = MapUtils.getLong(shortestDirectionMap, "distance", 0l);
					BigDecimal shortestDriveDistance = new BigDecimal(shortestDistance);
					BigDecimal shortestDriveDistanceBig = shortestDriveDistance.divide(BigDecimal.valueOf(1000L), 2,
							RoundingMode.DOWN);
					// 更新预计里程，最快里程，最短里程，最快里程赋值给预计里程
					workOrderTDao.updateMultiDistance(fastestDriveDistanceBig.toPlainString(),
							fastestDriveDistanceBig.toPlainString(), shortestDriveDistanceBig.toPlainString(),
							workOrderT.getId());
				}
				int updateWorkOrderResult = techDealWithWorkOrderDao.updateWorkOrderStatus(map);
				workOrderT = workOrderTDao.getWorkOrderTByOrderId(MapUtils.getLongValue(orderMap, "OrderId"));
				if (updateWorkOrderResult > 0) {
					// step2:插入工单操作记录
					// 准备操作记录参数
					map.put("OrderId", orderId);
					map.put("ProcessorId", map.get("userId"));
					map.put("OrderStatus", 10);// 此时工单状态为：已出发（10）
					map.put("ProLocLon", locLon);
					map.put("ProLocLat", locLat);
					map.put("ProLocation", location);
					map.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
					int saveOperation = workOrderRepairDao.saveOperation(map);
					if (saveOperation > 0) {
						// step3:同步工单状态至CRM
						Map<String, Object> tbMap = new HashMap<String, Object>();
						tbMap = convertMapToCRM(orderList, map);
						tbMap.put("positionLat", locLat);
						tbMap.put("positionLon", locLon);
						tbMap.put("location", location);
						tbMap.put("currentProvice", currentProvice);
						tbMap.put("currentCity", currentCity);
						tbMap.put("phoneIMEI", IMEI);
						tbMap.put("imei", IMEI);

						/**
						 * 2021-03-26 微信公众号开发增加需求 select OrderNo, OrderNoCrm, LocLon, LocLat, Location,
						 * LocationIsUpdated, LocProvince, LocCity from WorkOrder_T
						 */
						tbMap.put("faultLat", workOrderT.getLocLat());
						tbMap.put("faultLon", workOrderT.getLocLon());
						tbMap.put("faultLocation", workOrderT.getLocation());
						tbMap.put("locationIsUpdated", workOrderT.getLocationIsUpdated());
						tbMap.put("faultProvince", workOrderT.getLocProvince());
						tbMap.put("faultCity", workOrderT.getLocCity());
						// 2.10.0 ccec渠道需要重新传送预计，最快，最短里程到crm
						if (companyNo.toUpperCase().equals(CRMServiceConst.CCEC)) {
							tbMap.put("planMileage",
									workOrderT.getGuessDistance() != null ? workOrderT.getGuessDistance() : "");
							tbMap.put("fastestDistance",
									workOrderT.getFastestDistance() != null ? workOrderT.getFastestDistance() : "");
							tbMap.put("shortestDistance",
									workOrderT.getShortestDistance() != null ? workOrderT.getShortestDistance() : "");
						}
						if (workOrderT.getOrderChannel() == 1) {
							// 2.5.0 给crm传预估差旅小时数
							// 得到相差分钟数
							long durationMinutes = LocalTimeUtil.getDurationMinutes(LocalTimeUtil.getRealCurrentTime(),
									MapUtils.getString(map, "EstimatedTime", ""));
							if (durationMinutes > 0) {
								double durationHours = new BigDecimal((float) durationMinutes / 60)
										.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
								tbMap.put("estimatedTripHours", durationHours);
							} else {
								tbMap.put("estimatedTripHours", 0);
							}
						}
						// 异步处理，用户点击出发同步工单状态至CRM
						log.error("用户点击出发异步调用同步工单状态至CRM");
						asyncTask.asyncOrderStatusToCrm(companyNo, platformServiceDao, redisClientUtils, tbMap);
						// 处理当前负责人信息，并插入负责人表
						List<Map<String, Object>> batchList = new ArrayList<>();
						for (Map<String, Object> mmap : orderList) {
							Map<String, Object> principalMap = new HashMap<String, Object>();
							if (!"".equals(MapUtils.getString(mmap, "UserId", ""))) {
								principalMap.put("OrderId", orderId);
								principalMap.put("OrderStatus", 10);
								principalMap.put("IsPrincipal", MapUtils.getString(mmap, "IsPrincipal", "0"));
								principalMap.put("PrincipalId", mmap.get("UserId"));
								principalMap.put("ProcessorId", map.get("userId"));
								principalMap.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
								principalMap.put("Flag", 0);
								batchList.add(principalMap);
								// workOrderRepairDao.savePrincipal(principalMap);
							}
						}
						workOrderRepairDao.savePrincipalBatch(batchList);
						// step4:记录出发点轨迹
						Map<String, Object> trackMap = new HashMap<String, Object>();
						trackMap.put("OrderId", orderId);
						trackMap.put("LocLon", locLon);
						trackMap.put("LocLat", locLat);
						trackMap.put("Location", location);
						trackMap.put("IMEI", IMEI);
						trackMap.put("Flag", 0);
						trackMap.put("Creator", map.get("userId"));
						trackMap.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
						int saveTrack = techDealWithWorkOrderDao.saveOrderTrack(trackMap);
						// step5:给相关人员发送信息
						// 准备发送信息
						// ccec渠道给用户发的消息提醒和别的渠道一样 这里不做修改
						String stecSetOutBody = tecSetOutBody;
						stecSetOutBody = stecSetOutBody.replace("***", OrderNo);
						if(workOrderT.getOrderChannel() == 1){
							stecSetOutBody = stecSetOutBody + "属于\"" + workOrderT.getSellType() + "\"" + (StringUtils.isNotBlank(workOrderT.getServiceSubtype()) ? "-" + workOrderT.getServiceSubtype() : "") + "，";
						}
						stecSetOutBody = stecSetOutBody + "请查看!";
						String stecSetOutTransMsg = tecSetOutTransMsg;
						stecSetOutTransMsg = stecSetOutTransMsg.replace("***", OrderNo);
						if(workOrderT.getOrderChannel() == 1){
							stecSetOutTransMsg = stecSetOutTransMsg + "属于\"" + workOrderT.getSellType() + "\"" + (StringUtils.isNotBlank(workOrderT.getServiceSubtype()) ? "-" + workOrderT.getServiceSubtype() : "") + "，";
						}
						stecSetOutTransMsg = stecSetOutTransMsg + "请查看!";
						Map<String, Object> otherMap = new HashMap<String, Object>();
						otherMap.put("msgBody", stecSetOutBody);
						otherMap.put("msgTransMsg", stecSetOutTransMsg);
						otherMap.put("msgTitle", tecSetOutTitle);
						otherMap.put("function", tecFunction);
						otherMap.put("category", tecCategory);
						String cusPhone = MapUtils.getString(orderMap, "CustomerPhone");
						List<Map<String, Object>> customerList = techDealWithWorkOrderDao.getCustomerList(cusPhone);
						if (CollectionUtils.isEmpty(customerList)) {
							// 没有查询到该客户的信息，只给他发送短信，不用记录发送结果
							noticeService.sendSMS(4, 1, Long.parseLong(orderId), 0L, cusPhone, stecSetOutBody,
									MapUtils.getLongValue(map, "userId"));
							noticeService.push(4, 1, Long.parseLong(orderId), 0L, "", "新工单提醒", stecSetOutBody,
									stecSetOutBody, MapUtils.getLongValue(map, "userId"));
						} else {
							// 给该客户发送短信和APP消息，之后记录发送结果
							List<Map<String, Object>> cusSendResultList = asyncTask.sendMsg(map,
									customerList, 1, 1, otherMap);
							// 将发送结果记录入库
							if (CollectionUtils.isNotEmpty(cusSendResultList)) {
								workOrderRepairDao.saveMsgOperation(cusSendResultList);
							}
						}
						// dbu的工单需要推送公众号消息 dbu微信公众号查看工单详情url
						if (workOrderT.getOrderChannel() == 1) {
							String dbuWechatWorkOrderInfoUrl = propertiesUtils
									.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
							// 拼公众号中查看详情的url
							String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, orderId);
							// 推送微信公众号消息
							String firstData = "您有一条重要的工单状态信息";
							String keyWord1 = "编号：" + workOrderT.getOrderNo();
							String keyWord2 = "您的工单服务技师已出发，请查看。";
							String keyWord3 = Dictionaries.OrderStatus_10.getName();
							String keyWord4 = UserThreadLocal.get().getContact();
							String remark = "请点击详情查看工单内容";
							try {
								iOrderPushMessageService.sendOrderMessage(Long.parseLong(orderId), urlFormat, firstData,
										keyWord1, keyWord2, keyWord3, keyWord4, remark);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}

						int orderSource = workOrderT.getOrderSource();
						if (workOrderT.getOrderChannel() == 3 && orderSource == 6) {
							String dbuWechatWorkOrderInfoUrl = propertiesUtils
									.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
							// 拼公众号中查看详情的url
							String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, orderId);
							// 推送微信公众号消息
							String firstData = "您有一条重要的工单状态信息";
							String keyWord1 = "编号：" + workOrderT.getOrderNo();
							String keyWord2 = "您的工单服务技师已出发，请查看。";
							String keyWord3 = Dictionaries.OrderStatus_10.getName();
							String keyWord4 = UserThreadLocal.get().getContact();
							String remark = "请点击详情查看工单内容";
							try {
								iOrderPushMessageService.sendOrderMessage(Long.parseLong(orderId), urlFormat, firstData,
										keyWord1, keyWord2, keyWord3, keyWord4, remark);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
						// 给站长、信息员以及区域服务经理发APP消息
						// 根据服务站Id获取服务站的区域服务经理
						List<Map<String, Object>> areaManagerMap = new ArrayList<>();
						// ccec出发不给400角色推送
						orderMap.put("OrderChannel", orderMap.get("CompanyId"));
						if (workOrderT.getOrderChannel() != ccecChannelCompany.getId()) {
							orderMap.put("roleNo", "'R0070'");
							if (MapUtils.getIntValue(orderMap, "OrderChannel") == 1) {
								// dbu的区域工程师只推送指定的区域工程师
								areaManagerMap = workOrderRepairDao.getDBUAreaManager(Long.parseLong(orderId));
							} else {
								if (1==workOrderT.getIsTechSupport()) {
									//大工匠工单发送给大区经理
									areaManagerMap = workOrderRepairDao.getManager(orderMap);
								}else {
									// dcec和xcec还是原来的逻辑
									areaManagerMap = workOrderRepairDao.getAreaManager(orderMap);
								}

							}
						}
						// 根据服务站Id查询服务商站长和信息员
						orderMap.put("roleNo", "'R0041','R0069'");
						List<Map<String, Object>> SendList = workOrderRepairDao.getSendList(orderMap, Arrays.asList("R0041","R0069"));
						// 将两个查询结果合并
						/**
						 * 20210812 【短信通知】【XCEC】短信通知取消 取消以下短信发送： 1）区域经理 新工单提醒 实时发送：您有新工单信息，工单号XXX，请查看。
						 * 2）区域经理 新工单提醒（400指派给区域服务经理）实时发送：您有新工单信息，工单号XXX，请尽快处理。 3）区域经理 工单接受提醒
						 * 实时发送：您有工单被接受，工单号XXX，请查看。 4）区域经理 技师接单提醒 实时发送：您有工单被接单，工单号XXX，请查看。 5）区域经理
						 * 技师已出发提醒 实时发送：您的工单服务技师已出发，工单号XXX，请查看。- 当前，之前已完成 6）区域经理 技师开始维修提醒
						 * 实时发送：您的工单服务技师开始维修，工单号XXX，请查看。 7）区域经理 工单取消提醒 实时发送：您有工单取消，工单号XXX，请查看。 8）区域经理
						 * 服务商关闭工单提醒 实时发送：您有工单被关闭，工单号XXX，请查看。
						 */
						if (CollectionUtils.isNotEmpty(areaManagerMap)) {
							SendList.addAll(areaManagerMap);
						}
						if (CollectionUtils.isNotEmpty(SendList)) {
							// ccec渠道推送给站长和信息员的消息和别的渠道不一样 需要重新赋值
							if (workOrderT.getOrderChannel() == ccecChannelCompany.getId()) {
								String ccecZZMsg = "";
								if (StringUtils.isNotEmpty(workOrderT.getCCSSOrderNo())) {
									ccecZZMsg += "您的" + workOrderT.getOrderNo() + "号工单（FW号"
											+ workOrderT.getCCSSOrderNo() + "），服务技师已出发，请查看。";
								} else {
									ccecZZMsg += "您的" + workOrderT.getOrderNo() + "号工单，服务技师已出发，请查看。";
								}
								otherMap.put("msgBody", ccecZZMsg);
								otherMap.put("msgTransMsg", ccecZZMsg);
							}
							List<Map<String, Object>> sendResultList = new ArrayList<>();
							if (workOrderT.getOrderChannel() == ccecChannelCompany.getId()) { // ccec推送短信和app提醒，别的渠道看代码逻辑是只推送app提醒
								sendResultList = asyncTask.sendMsg(map, SendList, 1, 1, otherMap);
							} else {
								sendResultList = asyncTask.sendMsg(map, SendList, 0, 1, otherMap);
							}
							// 将发送结果入库
							if (CollectionUtils.isNotEmpty(sendResultList)) {
								workOrderRepairDao.saveMsgOperation(sendResultList);
							}
						}
						// step6将该工单外出轨迹在高德创建
						String createFlag = trackService.createTrace(orderMap);
						if ("missParam".equals(createFlag)) {
							ParameterTool.writeResponse(response, SMSEnum.type31.getIndex(), SMSEnum.type31.getName());
							// 主动回滚事务
							TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
							return null;
						} else if ("fail".equals(createFlag)) {
							ParameterTool.writeResponse(response, SMSEnum.type32.getIndex(), SMSEnum.type32.getName());
							// 主动回滚事务
							TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
							return null;
						}
						// 成功
						ParameterTool.writeSuccessResponse(response);
					}
				} else {
					// 返回客户
					// 主动回滚事务
					TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
					ParameterTool.writeResponse(response, SMSEnum.type21.getIndex(), SMSEnum.type21.getName());
					return null;
				}
			}
		} catch (NoTransactionException e) {
			log.error(e.getMessage(), e);
			ParameterTool.writeErrorResponse(response);
			// 主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
		return null;
	}

	// 服务技师接单和拒单
	@Override
	@Transactional
	public ModelAndView serviceTechnicianReceiveOrRefuseWorkOrder(Map<String, Object> map) {
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		HttpServletRequest request = (HttpServletRequest) map.get("request");
		try {
			String userADId = AESTool.decryptString(request.getHeader("userid"));// 解密userid
			UserT userT = loginDao.getUserByid(userADId);
			long userid = userT.getId();
			JSONObject obj = new JSONObject(); // 保存返给手机端的数据容器
			String workOrderId = (String) map.get("workOrderId"); // 工单id
			String strType = (String) map.get("type"); // 接单还是拒单type=1为接单，2为拒单
			String refuseReasonEngineer = "";
			if (map.containsKey("refuseReasonEngineer")) {
				refuseReasonEngineer = (String) map.get("refuseReasonEngineer"); // 服务技师拒单原因
			}
			if ("".equals(workOrderId) || workOrderId == null) {
				obj.put("data", "");
				obj.put("status", 1);
				obj.put("msg", "工单id不能为空!");
				ParameterTool.writeResponse(response, obj.toString());
				return null;
			}
			if ("".equals(strType) || strType == null) {
				obj.put("data", "");
				obj.put("status", 1);
				obj.put("msg", "未知工单操作类型,请确认接单还是拒单!");
				ParameterTool.writeResponse(response, obj.toString());
				return null;
			}
			CompanyT ccecChannelCompany = companyTDao.getCompanyInfoByCompanyNo("CCEC");
			CompanyT xcecChannelCompany = companyTDao.getCompanyInfoByCompanyNo("XCEC");
			int intType = Integer.parseInt(strType);
			map.put("ID", Long.parseLong(workOrderId));
			map.put("ServiceStationID", Long.parseLong((String) map.get("serviceStationId")));
			map.put("CompanyID", Long.parseLong((String) map.get("companyId")));
			// 获取服务站站长信息
//			List<UserT> zZUserTList = userTDao.getUserTByServiceStationId(map);
			// 获取服务站信息员信息
//			List<UserT> xXYUserTList = userTDao.getMsgUserTByServiceStationId(map);
			long organizationId = Long.parseLong((String) map.get("serviceStationId"));
			// 判断当前申请的是否是二网，如果是二网，则查找所属一网站长
			ServiceStationT serviceStation = serviceStationDao.findServiceStationByID(organizationId + "");
			int relationType = serviceStation.getRelationType() == null ? 1 : serviceStation.getRelationType();// 服务站类型，1-一网，2-二网
			List<UserT> zZAndXxyUserTList = null;
			if (relationType == 2) {// 如果是二网，查找所属一网站长
				zZAndXxyUserTList = userTDao.getStationMangerListByChildSSId(organizationId);
			} else {
				zZAndXxyUserTList = userTDao.getStationMasterListByServiceStationId(organizationId);
			}
			WorkOrderT workOrderT = workOrderTDao.getWorkOrderTById(map);
			// 1.服务技师接单拒单后保存工单信息，创建工单信息表map
			Map<String, Object> workOrderMap = new HashMap<String, Object>();
			String currentTime = LocalTimeUtil.getRealCurrentTime(); // 获取当前时间
			if (intType == 1) { // 接单操作
				workOrderMap.put("ReceiveTimeEngineer", currentTime); // 接单时间
				workOrderMap.put("OrderStatus", 8); // 工单状态服务技师已接单
			} else { // 拒单操作
				if (relationType == 2) {// 如果是二网，查找所属一网站点id，工单的站点id更新回去。
					workOrderMap.put("ServiceStationId", zZAndXxyUserTList.get(0).getServiceStationID()); 
				}
				workOrderMap.put("RefuseTimeEngineer", currentTime); // 拒单时间
				workOrderMap.put("RefuseReasonEngineer", refuseReasonEngineer); // 拒单原因
				workOrderMap.put("OrderStatus", 9); // 工单状态服务技师已拒单
			}
			workOrderMap.put("Updator", userid); // 修改人
			workOrderMap.put("UpdateTime", currentTime); // 修改时间
			workOrderMap.put("workOrderId", Long.parseLong(workOrderId)); // 工单id
			workOrderMap.put("OldUpdateTime", (String) map.get("updateTime")); // 前端传来的这条工单的修改时间
			int updateNum = techDealWithWorkOrderDao.serviceTechnicianReceiveOrRefuseWorkOrder(workOrderMap);// 保存工单
			if (updateNum == 0) { // 工单状态没修改成功
				obj.put("status", SMSEnum.type21.getIndex());
				obj.put("msg", SMSEnum.type21.getName());
				obj.put("data", "");
				// 返回客户
				ParameterTool.writeResponse(response, obj.toString());
				return null;
			}
			// 2.服务技师接单拒单后保存工单操作记录表信息，创建工单操作记录表map
			Map<String, Object> workOrderFlowTMap = new HashMap<String, Object>(); // 新建工单操作记录对象
			workOrderFlowTMap.put("OrderId", Long.parseLong(workOrderId)); // 工单id
			workOrderFlowTMap.put("ProcessorId", userid); // 处理人
			if (intType == 1) { // 接单操作
				workOrderFlowTMap.put("OrderStatus", 8); // 服务技师接单
			} else { // 拒单操作
				workOrderFlowTMap.put("OrderStatus", 9); // 服务技师拒单
			}
			workOrderFlowTMap.put("ProcessComment", refuseReasonEngineer); // 操作备注
			workOrderFlowTMap.put("ProLocLon", /*Float.parseFloat((String) map.get("locLon"))*/MapUtils.getFloatValue(map,"locLon",  0));
			workOrderFlowTMap.put("ProLocLat", /*Float.parseFloat((String) map.get("locLat"))*/MapUtils.getFloatValue(map,"locLat",  0));
			workOrderFlowTMap.put("ProLocation",  map.get("location"));
			workOrderFlowTMap.put("IMEI", map.get("IMEI")); // 手机串号
			workOrderFlowTMap.put("Flag", 0); // 是否删除(1为是，0为否)
			workOrderFlowTMap.put("Creator", userid); // 创建人
			workOrderFlowTMap.put("CreateTime", currentTime); // 处理时间
			workOrderRepairDao.saveOperation(workOrderFlowTMap); // 插入并保存工单操作记录数据
			// 3.服务技师接单拒单后保存工单负责人表信息，如果服务技师接单，工单主负责人就是服务技师，副负责人是副服务技师，如果服务技师拒单，工单主负责人就是站长和信息员
			// 如果服务技师接单，则存入主副服务技师信息到工单负责人表中
			// 如果是服务技师拒单，则存入服务站站长，信息员信息到工单信息表，并删除工单状态为待服务技师接单的工单负责人表中服务技师的数据
			// 通过工单id获取工单状态为待服务技师接单的所有工单负责人表的数据，主要为了拿到所有的服务技师数据
			List<WorkOrderPrincipalT> workOrderPrincipalTList = workOrderPrincipalTDao
					.getWorkOrderPrincipalTListByOrderId(map);
			if (intType == 1) { // 服务技师接单，主负责人就是服务技师，副负责人就是副服务技师
				// 新建服务技师工单负责人表map,保存主副服务技师
				if (CollectionUtils.isNotEmpty(workOrderPrincipalTList)) {
					for (WorkOrderPrincipalT workOrderPrincipalT : workOrderPrincipalTList) {
						Map<String, Object> FWJSWorkOrderPrincipalTMap = new HashMap<String, Object>();
						FWJSWorkOrderPrincipalTMap.put("OrderId", workOrderId);
						FWJSWorkOrderPrincipalTMap.put("OrderStatus", 8); // 工单状态为服务技师接单
						if (workOrderPrincipalT.getUserId() == userid) {
							FWJSWorkOrderPrincipalTMap.put("IsPrincipal", 1); // 是主负责人
						} else {
							FWJSWorkOrderPrincipalTMap.put("IsPrincipal", 0); // 是副负责人
						}
						FWJSWorkOrderPrincipalTMap.put("PrincipalId", workOrderPrincipalT.getUserId());
						FWJSWorkOrderPrincipalTMap.put("Audited", 0);
						FWJSWorkOrderPrincipalTMap.put("Flag", 0);
						FWJSWorkOrderPrincipalTMap.put("ProcessorId", userid);
						FWJSWorkOrderPrincipalTMap.put("CreateTime", currentTime);
						workOrderRepairDao.savePrincipal(FWJSWorkOrderPrincipalTMap); // 插入并保存工单负责人表数据
					}
				}
			} else { // 服务技师拒单，主负责人就是站长和信息员,删除之前工单状态为待服务技师接单的所有数据
				// 删除工单状态为待服务技师接单的工单负责人的信息数据(修改flag的值为-1即可)
				if (CollectionUtils.isNotEmpty(workOrderPrincipalTList)) {
					for (WorkOrderPrincipalT workOrderPrincipalT : workOrderPrincipalTList) {
						workOrderPrincipalTDao.deleteWorkOrderPrincipalTById(workOrderPrincipalT.getId(), userid,
								currentTime);
					}
				}
				// 判断服务站站长是否为空 站长和信息员
				if (CollectionUtils.isNotEmpty(zZAndXxyUserTList)) {
					for (UserT zZUserT : zZAndXxyUserTList) {
						// 新建服务站站长工单负责人表map
						if (zZUserT != null) {
							Map<String, Object> zhuWorkOrderPrincipalTMap = new HashMap<String, Object>();
							zhuWorkOrderPrincipalTMap.put("OrderId", workOrderId);
							zhuWorkOrderPrincipalTMap.put("OrderStatus", 9); // 工单状态为服务技师拒单
							zhuWorkOrderPrincipalTMap.put("IsPrincipal", 1); // 是主负责人
							zhuWorkOrderPrincipalTMap.put("PrincipalId", zZUserT.getId());
							zhuWorkOrderPrincipalTMap.put("Audited", 0);
							zhuWorkOrderPrincipalTMap.put("Flag", 0);
							zhuWorkOrderPrincipalTMap.put("ProcessorId", userid);
							zhuWorkOrderPrincipalTMap.put("CreateTime", currentTime);
							workOrderRepairDao.savePrincipal(zhuWorkOrderPrincipalTMap); // 插入并保存工单负责人表数据
						}
					}
				}
//				//判断服务站信息员集合是否为空
//				if(CollectionUtils.isNotEmpty(xXYUserTList)) {
//					for(UserT xXYUserT:xXYUserTList) {
//						//新建服务站信息员工单负责人表map
//						if(xXYUserT != null) {
//							Map<String, Object> zhuWorkOrderPrincipalTMap = new HashMap<String, Object>();
//							zhuWorkOrderPrincipalTMap.put("OrderId", workOrderId);
//							zhuWorkOrderPrincipalTMap.put("OrderStatus", 9);   //工单状态为待派服务技师
//							zhuWorkOrderPrincipalTMap.put("IsPrincipal", 1);   //是主负责人
//							zhuWorkOrderPrincipalTMap.put("PrincipalId",xXYUserT.getId());
//							zhuWorkOrderPrincipalTMap.put("Audited", 0);
//							zhuWorkOrderPrincipalTMap.put("Flag", 0);
//							zhuWorkOrderPrincipalTMap.put("ProcessorId",userid);
//							zhuWorkOrderPrincipalTMap.put("CreateTime", currentTime);
//							workOrderRepairDao.savePrincipal(zhuWorkOrderPrincipalTMap);   //插入并保存工单负责人表数据
//						}
//					}
//				}
			}
			// 4.服务技师接单拒单后保存消息提醒表信息，保存消息提醒表数据和进行短信和app推送
			// 新建消息提醒表对象list(可能会推送多人短信提醒)
			// 发送给客户的文字信息
			String customerMsg = "";
			String ccecCustomerMsg = ""; // ccec推送用户
			// 发送给服务站站长，信息员，区域服务经理的文字信息
			String otherMsg = "";
			String ccecOtherMsg = ""; // ccec推送给站长和信息员
			if (intType == 1) {
				customerMsg += "您的工单" + workOrderT.getOrderNo() + "已被技师接单，请查看。";
				otherMsg += "您有工单被接单，工单号" + workOrderT.getOrderNo() + "，";
				if(workOrderT.getOrderChannel() == 1){
					otherMsg = otherMsg + "属于\"" + workOrderT.getSellType() + "\"" + (StringUtils.isNotBlank(workOrderT.getServiceSubtype()) ? "-" + workOrderT.getServiceSubtype() : "") + "，";
				}
				otherMsg = otherMsg + "请查看。";
						ccecCustomerMsg += "您的工单已有技师接单，工单号" + workOrderT.getOrderNo() + "，请查看。";
				if (StringUtils.isNotEmpty(workOrderT.getCCSSOrderNo())) {
					ccecOtherMsg += "您有工单被接单，工单号" + workOrderT.getOrderNo() + "（FW号" + workOrderT.getCCSSOrderNo()
							+ "），请查看。";
				} else {
					ccecOtherMsg += "您有工单被接单，工单号" + workOrderT.getOrderNo() + "，请查看。";
				}
				if (workOrderT.getOrderChannel() == ccecChannelCompany.getId()) { // ccec渠道使用ccec专用推送消息
					customerMsg = ccecCustomerMsg;
					otherMsg = ccecOtherMsg;
				}
			} else {
				customerMsg += "您的工单" + workOrderT.getOrderNo() + "已被技师拒单，请查看。";
				otherMsg += "您有工单被拒单，工单号" + workOrderT.getOrderNo() + "，";
				if(workOrderT.getOrderChannel() == 1){
					otherMsg = otherMsg + "属于\"" + workOrderT.getSellType() + "\"" + (StringUtils.isNotBlank(workOrderT.getServiceSubtype()) ? "-" + workOrderT.getServiceSubtype() : "") + "，";
				}
				otherMsg = otherMsg + "请查看。";
				if (StringUtils.isNotEmpty(workOrderT.getCCSSOrderNo())) {
					ccecOtherMsg += "您有工单被拒单，工单号" + workOrderT.getOrderNo() + "（FW号" + workOrderT.getCCSSOrderNo()
							+ "），请查看。";
				} else {
					ccecOtherMsg += "您有工单被拒单，工单号" + workOrderT.getOrderNo() + "，请查看。";
				}
				if (workOrderT.getOrderChannel() == ccecChannelCompany.getId()) { // ccec渠道使用ccec专用推送消息
					otherMsg = ccecOtherMsg;
				}
			}
			// 服务技师接单，推送短信和app给客户，服务站站长，服务站信息员，区域服务经理消息；服务技师拒单，推送短信和app给服务站站长，服务站信息员
			List<Map<String, Object>> notifyRecordTMapList = new ArrayList<Map<String, Object>>();
			if (intType == 1) { // 服务技师接单，推送短信和app给客户，服务站站长，服务站信息员，区域服务经理消息
				// 给客户发送短信和app消息推送
				String customerPhone = workOrderT.getCustomerPhone(); // 客户的手机号
				SmsUtils.sendMessage(customerPhone, customerMsg); // 给客户发送短信
				// 先判断用户手机号是否在app中注册过，如果有，拿出用户id
				List<UserT> userTs = loginDao.getUserByPhone(customerPhone);
				Map<String, Object> customerNotifyRecordTMap = new HashMap<String, Object>();
				customerNotifyRecordTMap.put("OrderId", workOrderId);
				customerNotifyRecordTMap.put("Function", 4); // 技师响应提醒
				customerNotifyRecordTMap.put("Category", 1); // 新工单提醒
				if (CollectionUtils.isNotEmpty(userTs)) {
					customerNotifyRecordTMap.put("ReceiverId", userTs.get(0).getId()); // 接收人id
					customerNotifyRecordTMap.put("ExceptionInfo", "");
				} else {
					customerNotifyRecordTMap.put("ReceiverId", 0); // 接收人id
					customerNotifyRecordTMap.put("ExceptionInfo", "未查询到该用户");
				}
				customerNotifyRecordTMap.put("Content", customerMsg); // 内容
				customerNotifyRecordTMap.put("SendType", 1); // 短信提醒方式
				customerNotifyRecordTMap.put("SendTime", currentTime);
				customerNotifyRecordTMap.put("Status", 1); // 是否成功
				customerNotifyRecordTMap.put("IsRead", 0);
				customerNotifyRecordTMap.put("Flag", 0);
				customerNotifyRecordTMap.put("Creator", userid);
				customerNotifyRecordTMap.put("CreateTime", currentTime);
				notifyRecordTMapList.add(customerNotifyRecordTMap);
				// 推送App提醒消息
				if (CollectionUtils.isNotEmpty(userTs)) {
					noticeService.push(4, 1, Long.valueOf(workOrderId), userTs.get(0).getId(),
							userTs.get(0).getUserName(), "新工单提醒", customerMsg, customerMsg, userid);
				} else {
					noticeService.push(4, 1, Long.valueOf(workOrderId), 0L, "", "新工单提醒", customerMsg, customerMsg,
							userid);
				}
				// dbu的工单需要推送公众号消息 dbu微信公众号查看工单详情url
				if (workOrderT.getOrderChannel() == 1) {
					String dbuWechatWorkOrderInfoUrl = propertiesUtils.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
					// 拼公众号中查看详情的url
					String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, workOrderId);
					// 推送微信公众号消息
					String firstData = "您有一条重要的工单状态信息";
					String keyWord1 = "编号：" + workOrderT.getOrderNo();
//					String keyWord2 = "您的工单已被技师接单，请查看。";
					String keyWord2 = "您的工单已被技师" + (intType == 1 ? "接单" : "拒单") + "，请查看。";
					String keyWord3 = Dictionaries.OrderStatus_08.getName();
					String keyWord4 = UserThreadLocal.get().getContact();
					String remark = "请点击详情查看工单内容";
					iOrderPushMessageService.sendOrderMessage(Long.parseLong(workOrderId), urlFormat, firstData,
							keyWord1, keyWord2, keyWord3, keyWord4, remark);
				}
				// dcec的工单需要推送公众号消息 dcec微信公众号查看工单详情url
				Integer orderSource;
				try {
					orderSource = workOrderT.getOrderSource();
					if (workOrderT.getOrderChannel() == 3 && orderSource == 6) {
						String dbuWechatWorkOrderInfoUrl = propertiesUtils
								.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
						// Map<String, Object> weChatUserRelationTMap =
						// weChatUserRelationTDao.getWeChatUserRelationTByUserPhone(us.get(0).getPhone());
						// if (MapUtils.isNotEmpty(weChatUserRelationTMap)) {
						// 拼公众号中查看详情的url
						String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, workOrderId);
						// 推送微信公众号消息
						String firstData = "您有一条重要的工单状态信息";
						String keyWord1 = "编号：" + workOrderT.getOrderNo();
						String keyWord2 = "您的工单已被技师" + (intType == 1 ? "接单" : "拒单") + "，请查看。";
						String keyWord3 = Dictionaries.OrderStatus_08.getName();
						String keyWord4 = UserThreadLocal.get().getContact();
						String remark = "请点击详情查看工单内容";
						// ########################
						iOrderPushMessageService.sendOrderMessage(Long.parseLong(workOrderId), urlFormat, firstData,
								keyWord1, keyWord2, keyWord3, keyWord4, remark);

					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (workOrderT.getOrderChannel() != ccecChannelCompany.getId()) { // ccec技师接单只推送用户和站长，没有下面逻辑
					Map<String, Object> qygcsMap = new HashMap<>();
					if (workOrderT.getOrderChannel() == 1) { // DBU需求，只给指定的区域工程师推送消息
						qygcsMap = positionUserTDao.getDBUAreaManager(workOrderT.getId());
					}

					// 给区域服务经理发送短信和app消息推送，获取服务站对应的区域服务经理
					List<PositionUserT> positionUserTList = new ArrayList<>();
					if (1==workOrderT.getIsTechSupport()) {
						positionUserTList = positionUserTDao.getManager(map);
					}else {
						positionUserTList= positionUserTDao
								.getPostUserTListByServiceStationIdCompanyId(map);
					}

					if (CollectionUtils.isNotEmpty(positionUserTList)) {
						for (PositionUserT positionUserT : positionUserTList) {
							// 如果是dbu的工单，并且能获取出来区域工程师
							if (workOrderT.getOrderChannel() == 1 && MapUtils.isNotEmpty(qygcsMap)) {
								// 拿dbu指定的区域工程师手机号和上面的区域工程师集合循环比较，比较到了则推送，其他渠道工单不走此逻辑
								if (!(MapUtils.getString(qygcsMap, "DBEngineerPhone", "")
										.equals(positionUserT.getUserPhone()))) {
									continue;
								}
							}
							/**
							 * 20210812 【短信通知】【XCEC】短信通知取消 取消以下短信发送： 1）区域经理 新工单提醒 实时发送：您有新工单信息，工单号XXX，请查看。
							 * 2）区域经理 新工单提醒（400指派给区域服务经理）实时发送：您有新工单信息，工单号XXX，请尽快处理。 3）区域经理 工单接受提醒
							 * 实时发送：您有工单被接受，工单号XXX，请查看。 4）区域经理 技师接单提醒 实时发送：您有工单被接单，工单号XXX，请查看。- 当前 5）区域经理
							 * 技师已出发提醒 实时发送：您的工单服务技师已出发，工单号XXX，请查看。 6）区域经理 技师开始维修提醒
							 * 实时发送：您的工单服务技师开始维修，工单号XXX，请查看。 7）区域经理 工单取消提醒 实时发送：您有工单取消，工单号XXX，请查看。 8）区域经理
							 * 服务商关闭工单提醒 实时发送：您有工单被关闭，工单号XXX，请查看。
							 */
							Boolean status = false;
							if ((null == xcecChannelCompany)
									|| (workOrderT.getOrderChannel() != xcecChannelCompany.getId())) {
								SmsUtils.sendMessage(positionUserT.getUserPhone(), otherMsg); // 调用短信接口推送短信
								status = true;
							}
							// 先判断用户手机号是否在app中注册过，如果有，拿出用户id
							List<UserT> qyfwjls = loginDao.getUserByPhone(positionUserT.getUserPhone());
							if (status) {
								// 声明服务经理消息推送记录表map对象
								Map<String, Object> FWJLNotifyRecordTMap = new HashMap<String, Object>();
								FWJLNotifyRecordTMap.put("OrderId", workOrderId);
								FWJLNotifyRecordTMap.put("Function", 4); // 技师响应提醒
								FWJLNotifyRecordTMap.put("Category", 1); // 新工单提醒
								if (CollectionUtils.isNotEmpty(qyfwjls)) {
									FWJLNotifyRecordTMap.put("ReceiverId", qyfwjls.get(0).getId());
									FWJLNotifyRecordTMap.put("ExceptionInfo", "");
								} else {
									FWJLNotifyRecordTMap.put("ReceiverId", 0);
									FWJLNotifyRecordTMap.put("ExceptionInfo", "未查询到该用户");
								}
								FWJLNotifyRecordTMap.put("Content", otherMsg);
								FWJLNotifyRecordTMap.put("SendType", 1); // 短信方式
								FWJLNotifyRecordTMap.put("SendTime", currentTime);
								FWJLNotifyRecordTMap.put("Status", 1);
								FWJLNotifyRecordTMap.put("IsRead", 0);
								FWJLNotifyRecordTMap.put("Flag", 0);
								FWJLNotifyRecordTMap.put("Creator", userid);
								FWJLNotifyRecordTMap.put("CreateTime", currentTime);
								notifyRecordTMapList.add(FWJLNotifyRecordTMap); // 把区域服务经理消息推送记录添加到消息提醒表对象list中
							}
							// 推送App提醒消息
							if (CollectionUtils.isNotEmpty(qyfwjls)) {
								noticeService.push(4, 1, Long.valueOf(workOrderId), qyfwjls.get(0).getId(),
										qyfwjls.get(0).getUserName(), "新工单提醒", otherMsg, otherMsg, userid);
							}
						}
					}
				}
			}
			// 因为服务技师接单和拒单都给服务站站长和服务站信息员发送短信和app推送(只是提醒的话不一样)，所以写在一起
			// 给服务站站长和服务站信息员发送短信和app推送
			String receiveOtherMsg = "您有工单被接单，工单号" + workOrderT.getOrderNo() + "，";
			if(workOrderT.getOrderChannel() == 1){
				receiveOtherMsg = receiveOtherMsg + "属于\"" + workOrderT.getSellType() + "\"" + (StringUtils.isNotBlank(workOrderT.getServiceSubtype()) ? "-" + workOrderT.getServiceSubtype() : "") + "，";
			}
			receiveOtherMsg = receiveOtherMsg + "请查看。";
			String refuseOtherMsg = "您有工单被拒单，工单号" + workOrderT.getOrderNo() + "，";
			if(workOrderT.getOrderChannel() == 1){
				refuseOtherMsg = refuseOtherMsg + "属于\"" + workOrderT.getSellType() + "\"" + (StringUtils.isNotBlank(workOrderT.getServiceSubtype()) ? "-" + workOrderT.getServiceSubtype() : "") + "，";
			}
			refuseOtherMsg = refuseOtherMsg + "请查看。";
			String ccecReceiveOtherMsg = "";
			String ccecRefuseOtherMsg = "";
			if (StringUtils.isNotEmpty(workOrderT.getCCSSOrderNo())) {
				ccecReceiveOtherMsg += "您有工单被接单，工单号" + workOrderT.getOrderNo() + "（FW号" + workOrderT.getCCSSOrderNo()
						+ "），请查看。";
				ccecRefuseOtherMsg += "您有工单被拒单，工单号" + workOrderT.getOrderNo() + "（FW号" + workOrderT.getCCSSOrderNo()
						+ "），请查看。";
			} else {
				ccecReceiveOtherMsg += "您有工单被接单，工单号" + workOrderT.getOrderNo() + "，请查看。";
				ccecRefuseOtherMsg += "您有工单被拒单，工单号" + workOrderT.getOrderNo() + "，请查看。";
			}
			if (workOrderT.getOrderChannel() == ccecChannelCompany.getId()) { // ccec渠道使用ccec专用推送消息
				receiveOtherMsg = ccecReceiveOtherMsg;
				refuseOtherMsg = ccecRefuseOtherMsg;
			}
			// 判断服务站站长和信息员的集合是否为空
			if (CollectionUtils.isNotEmpty(zZAndXxyUserTList)) {
				for (UserT zZUserT : zZAndXxyUserTList) {
					SmsUtils.sendMessage(zZUserT.getPhone(), otherMsg); // 调用短信接口推送短信
					// 声明服务站站长消息推送记录表map对象
					Map<String, Object> zZNotifyRecordTMap = new HashMap<String, Object>();
					zZNotifyRecordTMap.put("OrderId", workOrderId);
					zZNotifyRecordTMap.put("Function", 4); // 技师响应提醒
					zZNotifyRecordTMap.put("Category", 1); // 新工单提醒
					zZNotifyRecordTMap.put("ReceiverId", zZUserT.getId());
					if (intType == 1) { // 接单
						zZNotifyRecordTMap.put("Content", receiveOtherMsg);
					} else { // 拒单
						zZNotifyRecordTMap.put("Content", refuseOtherMsg);
					}
					zZNotifyRecordTMap.put("SendType", 1); // 短信方式
					zZNotifyRecordTMap.put("SendTime", currentTime);
					zZNotifyRecordTMap.put("Status", 1);
					zZNotifyRecordTMap.put("ExceptionInfo", "");
					zZNotifyRecordTMap.put("IsRead", 0);
					zZNotifyRecordTMap.put("Flag", 0);
					zZNotifyRecordTMap.put("Creator", userid);
					zZNotifyRecordTMap.put("CreateTime", currentTime);
					notifyRecordTMapList.add(zZNotifyRecordTMap); // 把服务站站长消息推送记录添加到消息提醒表对象list中
					// 推送App提醒消息
					if (intType == 1) { // 接单
						noticeService.push(4, 1, Long.valueOf(workOrderId), zZUserT.getId(), zZUserT.getUserName(),
								"新工单提醒", receiveOtherMsg, receiveOtherMsg, userid);
					} else { // 拒单
						noticeService.push(4, 1, Long.valueOf(workOrderId), zZUserT.getId(), zZUserT.getUserName(),
								"新工单提醒", refuseOtherMsg, refuseOtherMsg, userid);
					}
				}
			}
			// 判断服务站信息员集合是否为空
//			if(xXYUserTList.size() != 0) {
//				for(UserT xXYUserT:xXYUserTList) {
//					SmsTool.sendSms(xXYUserT.getPhone(), otherMsg);  //调用短信接口推送短信
//					//声明服务站信息员消息推送记录表map对象
//					Map<String, Object> xXYNotifyRecordTMap = new HashMap<String, Object>();
//					xXYNotifyRecordTMap.put("OrderId", workOrderId);
//					xXYNotifyRecordTMap.put("Function", 4);  //技师响应提醒
//					xXYNotifyRecordTMap.put("Category", 1);  //新工单提醒
//					xXYNotifyRecordTMap.put("ReceiverId", xXYUserT.getId());
//					if(intType == 1) {  //接单
//						xXYNotifyRecordTMap.put("Content", receiveOtherMsg);
//					 }else {  //拒单
//						 xXYNotifyRecordTMap.put("Content", refuseOtherMsg);
//					 }
//					xXYNotifyRecordTMap.put("SendType", 1);  //短信方式
//					xXYNotifyRecordTMap.put("SendTime", currentTime);
//					xXYNotifyRecordTMap.put("Status", 1);
//					xXYNotifyRecordTMap.put("ExceptionInfo", "");
//					xXYNotifyRecordTMap.put("IsRead", 0);
//					xXYNotifyRecordTMap.put("Flag", 0);
//					xXYNotifyRecordTMap.put("Creator",userid);
//					xXYNotifyRecordTMap.put("CreateTime", currentTime);
//					notifyRecordTMapList.add(xXYNotifyRecordTMap);  //把服务站信息员消息推送记录添加到消息提醒表对象list中
//					//推送App提醒消息
//					if(intType == 1) {  //接单
//						noticeService.push(4,1,Long.valueOf(workOrderId),xXYUserT.getId(),xXYUserT.getUserName(),"新工单提醒",receiveOtherMsg,receiveOtherMsg,userid);
//					}else{
//						noticeService.push(4,1,Long.valueOf(workOrderId),xXYUserT.getId(),xXYUserT.getUserName(),"新工单提醒",refuseOtherMsg,refuseOtherMsg,userid);
//					}
//				}
//			}
			if (CollectionUtils.isNotEmpty(notifyRecordTMapList)) {
				workOrderRepairDao.saveMsgOperation(notifyRecordTMapList); // 保存消息推送记录表数据
			}
			// 把拒绝工单的信息详情同步到CRM
			Map<String, Object> parameters = new HashMap<String, Object>();
			parameters.put("orderNo", workOrderT.getOrderNo());
			if (intType == 1) {
				parameters.put("billStatus", 8);
			} else {
				parameters.put("billStatus", 9);
			}
			parameters.put("actionTime", currentTime);
			parameters.put("directorName", userT.getContact());
			parameters.put("directorPhone", userT.getPhone());
			parameters.put("refuseReason", refuseReasonEngineer);
			parameters.put("phoneIMEI", MapUtils.getString(map, "IMEI", ""));
			parameters.put("positionLat", MapUtils.getFloatValue(map, "locLat", 0));
			parameters.put("positionLon", MapUtils.getFloatValue(map, "locLon", 0));
			parameters.put("location", MapUtils.getString(map, "location", ""));
			if (workOrderT.getOrderChannel() == ccecChannelCompany.getId()) {
				parameters.put("imei", MapUtils.getString(map, "IMEI", ""));
				parameters.put("CCSSComplainerOrderNo", workOrderT.getOrderNoCrm());
				parameters.put("CCSSOrderNo", workOrderT.getCCSSOrderNo());
				parameters.put("customerName", workOrderT.getCustomerName());
				parameters.put("customerPhone", workOrderT.getCustomerPhone());
				parameters.put("customerCompany", workOrderT.getCustomerCompanyName());
				parameters.put("faultDesc", workOrderT.getCustomerComplaint());
				Map<String, Object> sSRepair = serviceStationDao.getStationNoAndNameByStationIdAndCompanyId(
						workOrderT.getServiceStationId(), workOrderT.getOrderChannel());
				if (org.apache.commons.collections.MapUtils.isNotEmpty(sSRepair)) {
					parameters.put("stationNo", sSRepair.get("BusinessNo"));
					parameters.put("stationName", sSRepair.get("StationName"));
				} else {
					parameters.put("stationNo", "");
					parameters.put("stationName", "");
				}
			}
			try {
				CRMResponeEntity crmResponeEntity = CRMApiUtils.getCRMServiceApi().syncOrderStatusToCrm(
						companyTDao.getCompanyInfoByCompanyID(workOrderT.getOrderChannel()).getCompanyNo(),
						platformServiceDao, redisClientUtils, parameters,null);
				if (crmResponeEntity.getStatus() != 0) {
					log.error("同步工单状态至CRM失败!状态:" + crmResponeEntity.getStatus() + ",错误信息:"
							+ crmResponeEntity.getMessage());
				}else {
					//更新工单表中的
					Object ocrUpdateFlag = crmResponeEntity.getData().get("OcrUpdateFlag");
					if (null!=ocrUpdateFlag) {
						if (StringUtils.isNotBlank(ocrUpdateFlag.toString())&&workOrderT.getOrderSource()!=1) {
							WorkOrderT workOrderTUpdate = new WorkOrderT();
							workOrderTUpdate.setOcrUpdateFlag(Integer.valueOf(ocrUpdateFlag.toString()));
							workOrderTUpdate.setId(workOrderT.getId());
							workOrderTDao.updateWorkOrderById(workOrderTUpdate);
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				log.error("同步工单状态至CRM失败!错误信息:" + e.getMessage(), e);
			}
			obj.put("data", "");
			obj.put("status", 0);
			if (intType == 1) {
				obj.put("msg", "服务技师接受工单成功!");
			} else {
				obj.put("msg", "服务技师拒绝工单成功!");
				// 技师拒单时，如果redis中有待服务技师接单超时原因，就删除
				Integer code = OverTimeType.TYPE2.getCode();
				String redisKey = "overTimeWorkOrderTypeKey-" + workOrderId + "-" + code;
				if (redisClientUtils.exists(redisKey)) {
					redisClientUtils.delkey(redisKey);
				}
			}
			ParameterTool.writeResponse(response, obj.toString());
		} catch (Exception e) {
			ParameterTool.writeErrorResponse(response);
			// 主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			log.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 技师点击到达按钮
	 * 
	 */
	@Transactional
	@Override
	public ModelAndView clickArrive(Map<String, Object> map) {

		// TODO Auto-generated method stub
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		HttpServletRequest request = (HttpServletRequest) map.get("request");
		JSONObject obj = new JSONObject();
		String currentProvice = MapUtils.getString(map, "Province", "");
		String currentCity = MapUtils.getString(map, "City", "");
		// 获取必要参数
		String OrderId = MapUtils.getString(map, "orderId", "");
		String PositionLon = MapUtils.getString(map, "positionLon", "");
		String PositionLat = MapUtils.getString(map, "positionLat", "");
		String Location = MapUtils.getString(map, "location", "");
		String IMEI = MapUtils.getString(map, "IMEI", "");
		String cusPhone = MapUtils.getString(map, "cusPhone", "");
		String ServiceStationId = MapUtils.getString(map, "serviceStationId", "");
		map.put("ProcessComment", "");
		map.put("arriveTime", LocalTimeUtil.getRealCurrentTime());
		map.put("OrderId", OrderId);
		map.put("PositionLon", PositionLon);
		map.put("PositionLat", PositionLat);
		map.put("Location", Location);
		map.put("ServiceStationId", ServiceStationId);
		// 获取实际当前时间(服务器时间加8小时)
		String realCurrentTime = LocalTimeUtil.getRealCurrentTime();
		map.put("OldUpdateTime", (String) map.get("updateTime"));
		map.put("updateTime", realCurrentTime);

		// 根据App传入字段userId查询user_T表ID
		UserT userT = UserThreadLocal.get();
		map.put("ProcessorId", userT.getId());
		if (null != userT) {
			long id = userT.getId();
			String contact = userT.getContact();
			String phone = userT.getPhone();
			map.put("userId", id);
			map.put("updator", id);
			map.put("contact", contact);
			map.put("phone", phone);
		}

		int isPrincipal = MapUtils.getIntValue(map, "IsPrincipal", 1); // 是否是主技师(0:否 1:是) 默认是1
		CompanyT ccecChannelCompany = companyTDao.getCompanyInfoByCompanyNo("CCEC");
		long orderId = Long.parseLong(OrderId);
		WorkOrderT workOrder = workOrderTDao.getWorkOrderTByOrderId(orderId);
		Map<String, Object> topOneOrderFlowMsgOrderByCreateTimeDesc = workOrderFlowTDao
				.getTopOneOrderFlowMsgOrderByCreateTimeDesc(orderId);
		if (isPrincipal == 1
				&& MapUtils.getIntValue(topOneOrderFlowMsgOrderByCreateTimeDesc, "processStatus", 0) == 11) { // 3.2.0
																												// 增加一层重复到达校验
																												// 判断工单最新一条时间轴是否是到达，若是到达则提示用户工单状态已变更
			obj.put("status", SMSEnum.type21.getIndex());
			obj.put("msg", SMSEnum.type21.getName());
			obj.put("data", "");
			// 主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			// 返回客户
			ParameterTool.writeResponse(response, obj.toString());
			return null;
		}
		if (workOrder.getOrderChannel() == ccecChannelCompany.getId() && isPrincipal == 0) { // ccec渠道的副技师点击到达 只记录操作信息
																								// 不修改工单
			// 获取到副技师在负责人表中主键di
			Map<String, Object> workOrderPrincipalMap = workOrderPrincipalTDao.getWorkOrderPrincipalByUserId(orderId,
					userT.getId());
			if (MapUtils.isNotEmpty(workOrderPrincipalMap)) {
				String currentTime = LocalTimeUtil.getRealCurrentTime();
				Map<String, Object> saveWorkOrderTechnicianOperatorMap = new HashMap<>();
				saveWorkOrderTechnicianOperatorMap.put("OrderStatus", 11);
				saveWorkOrderTechnicianOperatorMap.put("WorkOrderPrincipalId",
						MapUtils.getLongValue(workOrderPrincipalMap, "ID"));
				saveWorkOrderTechnicianOperatorMap.put("LocLon", PositionLon);
				saveWorkOrderTechnicianOperatorMap.put("LocLat", PositionLat);
				saveWorkOrderTechnicianOperatorMap.put("Location", Location);
				saveWorkOrderTechnicianOperatorMap.put("IMEI", IMEI);
				saveWorkOrderTechnicianOperatorMap.put("ReMark", "ccec副技师点击到达");
				saveWorkOrderTechnicianOperatorMap.put("Flag", 0);
				saveWorkOrderTechnicianOperatorMap.put("Creator", userT.getId());
				saveWorkOrderTechnicianOperatorMap.put("CreateTime", currentTime);
				techDealWithWorkOrderDao.saveWorkOrderTechnicianOperator(saveWorkOrderTechnicianOperatorMap);
				Map<String, Object> tbMap = new HashMap<String, Object>();
				tbMap.put("orderNo", workOrder.getOrderNo());
				tbMap.put("CCSSComplainerOrderNo", workOrder.getOrderNoCrm());
				tbMap.put("CCSSOrderNo", workOrder.getCCSSOrderNo());
				tbMap.put("billStatus", 11);
				tbMap.put("customerName", workOrder.getCustomerName());
				tbMap.put("customerPhone", workOrder.getCustomerPhone());
				tbMap.put("customerCompany", workOrder.getCustomerCompanyName());
				tbMap.put("faultDesc", workOrder.getCustomerComplaint());
				Map<String, Object> sSRepair = serviceStationDao.getSSRepairByStationIdAndCompanyId(
						workOrder.getServiceStationId(), workOrder.getOrderChannel());
				if (MapUtils.isNotEmpty(sSRepair)) {
					tbMap.put("stationNo", sSRepair.get("BusinessNo"));
				} else {
					tbMap.put("stationNo", "");
				}
				tbMap.put("actionTime", currentTime);
				tbMap.put("directorName", userT.getContact());
				tbMap.put("directorPhone", userT.getPhone());
				tbMap.put("assistEngineerName", userT.getContact());
				tbMap.put("engineerPhone", userT.getPhone());
				tbMap.put("positionLat", PositionLat);
				tbMap.put("positionLon", PositionLon);
				tbMap.put("location", Location);
				tbMap.put("currentProvice", currentProvice);
				tbMap.put("currentCity", currentCity);
				tbMap.put("phoneIMEI", IMEI);
				log.error("用户点击到达异步调用同步工单状态至CRM");
				asyncTask.asyncOrderStatusToCrm("CCEC", platformServiceDao, redisClientUtils, tbMap);
			}
			// 成功
			obj.put("status", 0);
			obj.put("msg", "success");
			obj.put("data", "");
			// 返回客户
			ParameterTool.writeResponse(response, obj.toString());
		} else {
			// 根据工单ID查询外出跟踪表WorkOrderTrack_T中IEMI（手机串号），同步工单状态到CRM中使用
			List<Map<String, Object>> workOrderTrack = techDealWithWorkOrderDao.getWorkOrderTrack(map);

			if (workOrderTrack.size() > 1) {

				// 拼接字符串
				String pIMEI = "";
				for (Map<String, Object> wt : workOrderTrack) {
					pIMEI += MapUtils.getString(wt, "IMEI") + ",";
				}
				String phoneIMEI = pIMEI.substring(0, pIMEI.length() - 1);
				map.put("phoneIMEI", phoneIMEI);
			} else {
				map.put("phoneIMEI", IMEI);
			}
			double realDistance = MapUtils.getDouble(map, "realDistance", 0.0);
			if(realDistance <= 0){
				Map<String, Object> commonMap = new HashMap<>();
				commonMap.put("orderId",OrderId);
				commonMap.put("positionLon",PositionLon);
				commonMap.put("positionLat",PositionLat);
				Map<String, Object> data = getCommonRealDistance(commonMap);
				if(MapUtils.isNotEmpty(data)){
					map.put("realDistance",data.get("driveDistance"));
				}
			}
			// 变更工单状态（技师点击已到达，工单状态变为已到达）
			int updateWorkOrderResult = techDealWithWorkOrderDao.upWorkOrderStatus(map);

			if (updateWorkOrderResult > 0) {
				// 根据页面传过来的工单Id查询工单最新状态
				Map<String, Object> workOrderMap = new HashMap<String, Object>();
				workOrderMap = confirmationByServiceManagerDao.getCurrentWorkOrder(map);
				if (workOrderMap != null) {
					List<Map<String, Object>> batchList = new ArrayList();
					// 根据工单ID查询负责人表
					List<Map<String, Object>> workOrderPrincipal = techDealWithWorkOrderDao.getWorkOrderPrincipal(map);
					for (Map<String, Object> wt : workOrderPrincipal) {
						Map<String, Object> newmap = new HashMap<>();
						newmap.put("OrderId", wt.get("OrderId"));
						newmap.put("OrderStatus", 11);
						newmap.put("IsPrincipal", wt.get("IsPrincipal"));
						newmap.put("PrincipalId", wt.get("UserId"));
						newmap.put("Audited", wt.get("Audited"));
						newmap.put("Flag", wt.get("Flag"));
						newmap.put("ProcessorId", wt.get("Creator"));
						newmap.put("CreateTime", realCurrentTime);
						// 插入工单负责人表
						// int insertWorkOrderPrincipal =
						// serviceManagerAffirmDao.insertWorkOrderPrincipal(newmap);
						// int insertWorkOrderPrincipal = workOrderRepairDao.savePrincipal(newmap);
						batchList.add(newmap);
					}
					int insertWorkOrderPrincipal = workOrderRepairDao.savePrincipalBatch(batchList);
				}

				String orderNo = MapUtils.getString(workOrderMap, "OrderNo");
				// 将工单状态同步至CRM接口
				// 字段转换（APP接口字段名与CRM接口字段名不一致。）
				Map<String, Object> tbMap2 = new HashMap<String, Object>();
				tbMap2 = OrderStatusToCrmMap(workOrderMap, map);
				tbMap2.put("positionLat", PositionLat);
				tbMap2.put("positionLon", PositionLon);
				tbMap2.put("location", Location);
				tbMap2.put("currentProvice", currentProvice);
				tbMap2.put("currentCity", currentCity);
				tbMap2.put("phoneIMEI", IMEI);
				tbMap2.put("imei", IMEI);
				if (workOrder.getOrderChannel() == 1) {
					// 2.5.0 给crm传实际差旅小时数
					// 得到出发的时间
					Map<String, Object> workOrderFlow = workOrderFlowTDao
							.getWorkOrderFlowByOrderAndStatus(workOrder.getId(), 10);
					if (MapUtils.isNotEmpty(workOrderFlow)) {
						// 得到相差分钟数
						long durationMinutes = LocalTimeUtil.getDurationMinutes(
								MapUtils.getString(workOrderFlow, "CreateTime", ""),
								LocalTimeUtil.getRealCurrentTime());
						if (durationMinutes > 0) {
							double durationHours = new BigDecimal((float) durationMinutes / 60)
									.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
							tbMap2.put("tripHours", durationHours);
						}
					}
					if (!tbMap2.containsKey("tripHours")) {
						tbMap2.put("tripHours", 0);
					}
				}
				log.error("用户点击到达异步调用同步工单状态至CRM");
				asyncTask.asyncOrderStatusToCrm(workOrderMap.get("Abbreviation").toString(), platformServiceDao,
						redisClientUtils, tbMap2);
				// 插入工单操作记录表
				map.put("ProcessStatus", 11);
				int insertWorkOrderFlow2 = serviceManagerAffirmDao.insertWorkOrderFlow(map);

				// 准备发送信息
				Map<String, Object> otherMap = new HashMap<String, Object>();
				String smsgbody = "您的工单服务技师已到达，工单号" + orderNo + "，";
				if(workOrder.getOrderChannel() == 1){
					smsgbody = smsgbody + "属于\"" + workOrder.getSellType() + "\"" + (StringUtils.isNotBlank(workOrder.getServiceSubtype()) ? "-" + workOrder.getServiceSubtype() : "") + "，";
				}
				smsgbody  = smsgbody + "请查看！";
				String stransmsg = "您的工单服务技师已到达，工单号" + orderNo + "，";
				if(workOrder.getOrderChannel() == 1){
					stransmsg = stransmsg + "属于\"" + workOrder.getSellType() + "\"" + (StringUtils.isNotBlank(workOrder.getServiceSubtype()) ? "-" + workOrder.getServiceSubtype() : "") + "，";
				}
				stransmsg = stransmsg + "请查看!";
				String ccecYHMsg = "您的工单服务技师已到达，准备开始维修，工单号" + workOrder.getOrderNo() + "，请查看。"; // ccec给用户提示信息
				if (workOrder.getOrderChannel() == ccecChannelCompany.getId()) { // ccec渠道重新赋值 使用ccec的提示语
					otherMap.put("msgBody", ccecYHMsg);
					otherMap.put("msgTransMsg", ccecYHMsg);
				} else {
					otherMap.put("msgBody", smsgbody);
					otherMap.put("msgTransMsg", stransmsg);
				}
				otherMap.put("msgTitle", "新工单提醒");
				otherMap.put("function", 5);
				otherMap.put("category", 1);

				// 给客户发信息（根据原生传过来的手机号查询该客户是否在系统内）
				List<Map<String, Object>> customerList = new ArrayList<Map<String, Object>>();
				customerList = techDealWithWorkOrderDao.getCustomerList(cusPhone);
				if (CollectionUtils.isNotEmpty(customerList)) {
					// 给该客户发送APP消息，之后记录发送结果
					List<Map<String, Object>> cusSendResultList = new ArrayList<Map<String, Object>>();
					if (workOrder.getOrderChannel() == ccecChannelCompany.getId()) { // ccec是推送app和短信 其他渠道的看代码都是只推送app
						cusSendResultList = asyncTask.sendMsg(map, customerList, 1, 1, otherMap);
					} else {
						cusSendResultList = asyncTask.sendMsg(map, customerList, 0, 1, otherMap);
					}
					// 将发送结果记录入库
					if (CollectionUtils.isNotEmpty(cusSendResultList)) {
						int cusSaveSendResult = workOrderRepairDao.saveMsgOperation(cusSendResultList);
					}
				} else {
					noticeService.sendSMS(4, 1, orderId, 0L, cusPhone, MapUtils.getString(otherMap, "msgBody", ""),
							userT.getId());
					noticeService.push(4, 1, orderId, 0L, "", "新工单提醒", MapUtils.getString(otherMap, "msgBody", ""),
							MapUtils.getString(otherMap, "msgBody", ""), userT.getId());
				}

				// dbu的工单需要推送公众号消息 dbu微信公众号查看工单详情url
				if (workOrder.getOrderChannel() == 1) {
					String dbuWechatWorkOrderInfoUrl = propertiesUtils.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
					// Map<String, Object> weChatUserRelationTMap =
					// weChatUserRelationTDao.getWeChatUserRelationTByUserPhone(us.get(0).getPhone());
					// if (MapUtils.isNotEmpty(weChatUserRelationTMap)) {
					// 拼公众号中查看详情的url
					String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, orderId);
					// 推送微信公众号消息
					String firstData = "您有一条重要的工单状态信息";
					String keyWord1 = "编号：" + workOrder.getOrderNo();
					String keyWord2 = "您的工单服务技师已到达，请查看。";
					String keyWord3 = Dictionaries.OrderStatus_11.getName();
					String keyWord4 = UserThreadLocal.get().getContact();
					String remark = "请点击详情查看工单内容";
					try {
						iOrderPushMessageService.sendOrderMessage(orderId, urlFormat, firstData, keyWord1, keyWord2,
								keyWord3, keyWord4, remark);
					} catch (Exception e) {
						e.printStackTrace();
					}
					// }
				}
				// dcec的工单需要推送公众号消息 dcec微信公众号查看工单详情url

				Integer orderSource;
				try {
					orderSource = workOrder.getOrderSource();
					if (workOrder.getOrderChannel() == 3 && orderSource == 6) {
						String dbuWechatWorkOrderInfoUrl = propertiesUtils
								.getPropertiesValue("DBUWechatWorkOrderInfoUrl");
						// Map<String, Object> weChatUserRelationTMap =
						// weChatUserRelationTDao.getWeChatUserRelationTByUserPhone(us.get(0).getPhone());
						// if (MapUtils.isNotEmpty(weChatUserRelationTMap)) {
						// 拼公众号中查看详情的url
						String urlFormat = String.format(dbuWechatWorkOrderInfoUrl, workOrder.getId());
						// 推送微信公众号消息
						String firstData = "您有一条重要的工单状态信息";
						String keyWord1 = "编号：" + workOrder.getOrderNo();
						String keyWord2 = "您的工单服务技师已到达，请查看。";
						String keyWord3 = Dictionaries.OrderStatus_11.getName();
						String keyWord4 = UserThreadLocal.get().getContact();
						String remark = "请点击详情查看工单内容";
						// ########################
						iOrderPushMessageService.sendOrderMessage(workOrder.getId(), urlFormat, firstData, keyWord1,
								keyWord2, keyWord3, keyWord4, remark);

					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				map.put("roleNames", "'站长','服务商信息员','区域服务经理','终端用户'");
				map.put("roleNo", "'R0041','R0069'");
				String ccecOtherMsg = ""; // ccec推送给站长信息
				if (workOrder.getOrderChannel() == ccecChannelCompany.getId()) { // ccec渠道重新赋值 使用ccec的提示语
					if (StringUtils.isNotEmpty(workOrder.getCCSSOrderNo())) {
						ccecOtherMsg += "您的" + workOrder.getOrderNo() + "号工单（FW号" + workOrder.getCCSSOrderNo()
								+ "）服务技师已到达，请查看。";
					} else {
						ccecOtherMsg += "您的" + workOrder.getOrderNo() + "号工单服务技师已到达，请查看。";
					}
					otherMap.put("msgBody", ccecOtherMsg);
					otherMap.put("msgTransMsg", ccecOtherMsg);
				} else {
					otherMap.put("msgBody", smsgbody);
					otherMap.put("msgTransMsg", stransmsg);
				}
				List<Map<String, Object>> sendList = new ArrayList<Map<String, Object>>();
				sendList = workOrderRepairDao.getSendList(map,Arrays.asList("R0041","R0069"));
				// ccec技师到达不通知400 别的渠道走下面的if逻辑
				if (workOrder.getOrderChannel() != ccecChannelCompany.getId()) {
					// 根据服务站Id获取服务站的区域服务经理
					List<Map<String, Object>> areaManagerMap = new ArrayList<Map<String, Object>>();
					map.put("roleNo", "'R0070'");
					map.put("OrderChannel", workOrderMap.get("OrderChannel"));
					if (MapUtils.getIntValue(map, "OrderChannel") == 1) {
						// dbu的区域工程师只推送指定的区域工程师
						areaManagerMap = workOrderRepairDao.getDBUAreaManager(Long.parseLong(OrderId));
					} else {
						// dcec和xcec还是原来的逻辑
						if (1==workOrder.getIsTechSupport()) {
							areaManagerMap=workOrderRepairDao.getManager(map);
						}else {
							areaManagerMap = workOrderRepairDao.getAreaManager(map);
						}
					}
					// 将两个查询结果合并
					if (null != areaManagerMap && areaManagerMap.size() > 0) {
						sendList.addAll(areaManagerMap);
					}
				}

				workOrderMap.put("ProcessorId", userT.getId());
				if (null != sendList && sendList.size() > 0) {
					// 开始发送消息(返回结果集为发送结果，要存入数据库，作为记录)
					List<Map<String, Object>> sendMsgResultList = new ArrayList<>();
					if (workOrder.getOrderChannel() == ccecChannelCompany.getId()) { // ccec是推送app和短信 其他渠道的看代码都是只推送app
						sendMsgResultList = asyncTask.sendMsg(workOrderMap, sendList, 1, 1, otherMap);
					} else {
						sendMsgResultList = asyncTask.sendMsg(workOrderMap, sendList, 0, 1, otherMap);
					}

					// 将信息发送结果记录到数据库
					if (CollectionUtils.isNotEmpty(sendMsgResultList)) {
						int saveMsgOperationResult = workOrderRepairDao.saveMsgOperation(sendMsgResultList);
					}
				}
				obj.put("status", 0);
				obj.put("msg", "");
				obj.put("data", "");
				ParameterTool.writeResponse(response, obj.toString());
			} else {
				obj.put("status", SMSEnum.type21.getIndex());
				obj.put("msg", SMSEnum.type21.getName());
				obj.put("data", "");
				// 主动回滚事务
				TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
				// 返回客户
				ParameterTool.writeResponse(response, obj.toString());
				return null;
			}
		}
		return null;

	}

	/**
	 * 将工单状态同步至CRM(由于CRM接口与APP接口的字段名称不一致，所以要进行相关字段的转换)
	 * 
	 * @param map 工单来源（0：客户，1：服务站）
	 * @return
	 */
	public Map<String, Object> OrderStatusToCrmMap(Map<String, Object> orgOrderMap, Map<String, Object> map) {
		Map<String, Object> tbMap = new HashMap<String, Object>();
		tbMap.put("orderNo", orgOrderMap.get("OrderNo"));
		if (!"".equals(MapUtils.getString(orgOrderMap, "OrderNoCrm", ""))) {
			tbMap.put("CRMNo", orgOrderMap.get("OrderNoCrm"));
		}
		tbMap.put("billStatus", 11);
		tbMap.put("actionTime", LocalTimeUtil.getRealCurrentTime());
		tbMap.put("directorName", map.get("contact"));
		tbMap.put("directorPhone", map.get("phone"));
		tbMap.put("phoneIMEI", map.get("phoneIMEI"));
		tbMap.put("planMileage", orgOrderMap.get("GuessDistance"));
		tbMap.put("travelMileage", map.get("realDistance"));
		tbMap.put("reviseMileage", map.get("adjustDistance"));
		if (map.containsKey("BusinessNo")) {
			tbMap.put("stationNo", map.get("BusinessNo"));
		}
		tbMap.put("fastestDistance", MapUtils.getString(orgOrderMap, "FastestDistance", ""));
		tbMap.put("shortestDistance", MapUtils.getString(orgOrderMap, "ShortestDistance", ""));

		return tbMap;
	}

	@Transactional
	@Override
	public ModelAndView outGoingTrack(Map<String, Object> map) {
		// TODO Auto-generated method stub
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		HttpServletRequest request = (HttpServletRequest) map.get("request");
		try {
			JSONObject obj = new JSONObject();
			// 获取必要参数
			String orderIdArrs = MapUtils.getString(map, "orderId", "");
			String userId = MapUtils.getString(map, "userId", "");
			String locLon = MapUtils.getString(map, "locLon", "");
			String locLat = MapUtils.getString(map, "locLat", "");
			String location = MapUtils.getString(map, "location", "");
			String IMEI = MapUtils.getString(map, "IMEI", "");
			String[] orderIdArr = orderIdArrs.split(",");
			if (orderIdArr.length == 0 || "".equals(userId) || "".equals(locLon) || "".equals(locLat)
					|| "".equals(location) || "".equals(IMEI)) {
				// 丢失必要参数
				obj.put("status", SMSEnum.type17.getIndex());
				obj.put("msg", SMSEnum.type17.getName());
				obj.put("data", "");
				// 返回客户
				ParameterTool.writeResponse(response, obj.toString());
				obj = null;
				return null;
			}
			// 根据用户Id获取用户信息
			String UserId = map.get("userId").toString();
			UserT ut = loginDao.getUserByid(UserId);
			if (null != ut) {
				long lUserId = ut.getId();
				map.put("userId", lUserId);
			} else {
				// 丢失必要参数
				obj.put("status", SMSEnum.type18.getIndex());
				obj.put("msg", SMSEnum.type18.getName());
				obj.put("data", "");
				// 返回客户
				ParameterTool.writeResponse(response, obj.toString());
				obj = null;
				return null;
			}
			DecimalFormat df = new DecimalFormat("#.000000");
			// step1:记录出发点轨迹
			for (int i = 0; i < orderIdArr.length; i++) {
				Map<String, Object> trackMap = new HashMap<String, Object>();
				trackMap.put("OrderId", orderIdArr[i]);
				trackMap.put("LocLon", df.format(Double.parseDouble(locLon)));
				trackMap.put("LocLat", df.format(Double.parseDouble(locLat)));
				trackMap.put("Location", location);
				trackMap.put("IMEI", IMEI);
				trackMap.put("Flag", 0);
				trackMap.put("Creator", map.get("userId"));
				trackMap.put("CreateTime", LocalTimeUtil.getRealCurrentTime());
				int saveTrack = techDealWithWorkOrderDao.saveOrderTrack(trackMap);
			}
			// 查询当前技师未完成工单
			List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
			Map<String, Object> param = new HashMap<String, Object>();
			param.put("UserId", map.get("userId"));
			list = workOrderTDao.getInServiceOrderListByUserId(param);
			// 上传经纬度成功
			obj.put("status", SMSEnum.type0.getIndex());
			obj.put("msg", SMSEnum.type0.getName());
			obj.put("data", list);
			ParameterTool.writeResponse(response, obj.toString());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			ParameterTool.writeErrorResponse(response);
			// 主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			e.printStackTrace();
		}
		return null;
	}

	@Override
	@Transactional
	public ModelAndView newOutGoingTrack(Map<String, Object> map) {
		// TODO Auto-generated method stub
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		try {
			UserT userT = UserThreadLocal.get();
			String IMEI = MapUtils.getString(map, "IMEI", "");
			List<Object> orderLocationList = (List<Object>) MapUtils.getObject(map, "orderLocations");
			if (CollectionUtils.isNotEmpty(orderLocationList)) {
				DecimalFormat df = new DecimalFormat("#.000000");
				for (Object orderLocation : orderLocationList) {
					Map<String, Object> orderLocationMap = (Map<String, Object>) orderLocation;
					Long orderId = MapUtils.getLong(orderLocationMap, "orderId");
					WorkOrderT workOrderT = workOrderTDao.getWorkOrderTByOrderId(orderId);
					if (null != workOrderT) {
						List<Map<String, Object>> locationMapList = (List<Map<String, Object>>) orderLocationMap
								.get("locations");
						if (CollectionUtils.isNotEmpty(locationMapList)) {
							if (workOrderT.getOrderStatus() == 10) { // 10 当前订单为出发状态
								// TODO === 订单轨迹中保存订单的状态
								// 出发中，将经纬度点发送高德并本地保存数据
								saveTracks(locationMapList, orderId, IMEI, userT.getId(), workOrderT.getOrderStatus());
								trackService.uploadTrace(workOrderT, locationMapList, IMEI);
							} else {
								// 非出发中状态，直接将经纬度点存入数据库
								saveTracks(locationMapList, orderId, IMEI, userT.getId(), workOrderT.getOrderStatus());
							}
						}
					}
				}
			}
			Map<String, Object> param = new HashMap<>();
			param.put("UserId", userT.getId());
			List<Map<String, Object>> list = workOrderTDao.getInServiceOrderListByUserId(param);
			// 上传经纬度成功
			ParameterTool.writeSuccessResponse(response, list);
		} catch (Exception e) {
			// 主动回滚事务
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			// TODO Auto-generated catch block
			ParameterTool.writeErrorResponse(response);
			log.error(e.getMessage(), e);
		}
		return null;
	}

	private void saveTracks(List<Map<String, Object>> locationMapList, Long orderId, String IMEI, Long userId,
			Integer orderStatus) {
		DecimalFormat df = new DecimalFormat("#.000000");
		if (CollectionUtils.isEmpty(locationMapList)) {
			return;
		}
		Integer size = locationMapList.size();
		Map<String, Object> lastTrack = locationMapList.get(size - 1);
		Map<String, Object> trackMap = new HashMap<String, Object>();
		trackMap.put("orderId", orderId);
		trackMap.put("locLon", df.format(MapUtils.getDouble(lastTrack, "locLon")));
		trackMap.put("locLat", df.format(MapUtils.getDouble(lastTrack, "locLat")));
		trackMap.put("location", lastTrack.get("location"));
		trackMap.put("imei", IMEI);
		trackMap.put("flag", 0);
		trackMap.put("creator", userId);
		trackMap.put("createTime", Date_Util.GetTimeByTimesTamp(MapUtils.getLong(lastTrack, "timestamp")));
		trackMap.put("orderStatus", orderStatus);
		workOrderTrackTDao.insert(trackMap);
		/*
		 * List<Map<String,Object>> saveTrackList = new ArrayList<>();
		 * for(Map<String,Object> locationMap:locationMapList) { Map<String, Object>
		 * trackMap = new HashMap<String, Object>(); trackMap.put("orderId", orderId);
		 * trackMap.put("locLon", df.format(MapUtils.getDouble(locationMap,"locLon")));
		 * trackMap.put("locLat", df.format(MapUtils.getDouble(locationMap,"locLat")));
		 * trackMap.put("location", locationMap.get("location")); trackMap.put("imei",
		 * IMEI); trackMap.put("flag", 0); trackMap.put("creator", userId);
		 * trackMap.put("createTime",
		 * Date_Util.GetTimeByTimesTamp(MapUtils.getLong(locationMap,"timestamp")));
		 * saveTrackList.add(trackMap); }
		 * 
		 * if(CollectionUtils.isNotEmpty(saveTrackList)){ Integer size =
		 * saveTrackList.size(); Integer startIndex = 0; Integer endIndex = 0; while
		 * (endIndex < size){ endIndex = startIndex + BATCH_LIMIT > size ? size:
		 * startIndex + BATCH_LIMIT; List<Map<String,Object>> subTrackList =
		 * saveTrackList.subList(startIndex,endIndex);
		 * workOrderTrackTDao.batchInsert(subTrackList); startIndex = endIndex; } }
		 */
	}

	public Map<String, Object> convertMapToCRM(List<Map<String, Object>> orderList, Map<String, Object> map) {
		Map<String, Object> crmMap = new HashMap<String, Object>();
		// 处理主副技师信息
		String directorName = "";// 主技师名字
		String directorPhone = "";// 主技师电话
		String assistEngineerName = "";// 副技师名字，多个用逗号隔开
		String engineerPhone = "";// 副技师电话，多个用逗号隔开
		for (Map<String, Object> mmap : orderList) {
			String IsPrincipal = MapUtils.getString(mmap, "IsPrincipal", "");
			if ("1".equals(IsPrincipal)) {
				// 主技师信息
				directorName = MapUtils.getString(mmap, "Contact", "");
				directorPhone = MapUtils.getString(mmap, "phone");
			} else if ("0".equals(IsPrincipal)) {
				// 副技师信息
				String userName = MapUtils.getString(mmap, "Contact", "");
				if (!"".equals(userName)) {
					assistEngineerName += userName + ",";
				}
				String phone = MapUtils.getString(mmap, "phone", "");
				if (!"".equals(phone)) {
					engineerPhone += phone + ",";
				}
			}
		}
		// 副技师信息不为空，去掉结尾的逗号
		if (assistEngineerName.length() > 0) {
			assistEngineerName = assistEngineerName.substring(0, assistEngineerName.length() - 1);
		}
		if (engineerPhone.length() > 0) {
			engineerPhone = engineerPhone.substring(0, engineerPhone.length() - 1);
		}
		// 工单的基本信息
		Map<String, Object> orgMap = new HashMap<String, Object>();
		orgMap = orderList.get(0);
		if (StringUtils.isNotBlank(MapUtils.getString(orgMap, "OrderNo", ""))) {
			crmMap.put("orderNo", MapUtils.getString(orgMap, "OrderNo", ""));
		}
		if (StringUtils.isNotBlank(MapUtils.getString(orgMap, "OrderNoCrm", ""))) {
			crmMap.put("CRMNo", MapUtils.getString(orgMap, "OrderNoCrm", ""));
		}
		// 当前工单状态为 技师已出发（10）
		crmMap.put("billStatus", 10);
		// 操作时间
		crmMap.put("actionTime", LocalTimeUtil.getRealCurrentTime());

		if (StringUtils.isNotBlank(directorName)) {
			crmMap.put("directorName", directorName);
		}
		if (StringUtils.isNotBlank(directorPhone)) {
			crmMap.put("directorPhone", directorPhone);
		}
		if (StringUtils.isNotBlank(assistEngineerName)) {
			crmMap.put("assistEngineerName", assistEngineerName);
		}
		if (StringUtils.isNotBlank(engineerPhone)) {
			crmMap.put("engineerPhone", engineerPhone);
		}
		if (StringUtils.isNotBlank(MapUtils.getString(orgMap, "GuessDistance", ""))) {
			crmMap.put("planMileage", MapUtils.getString(orgMap, "GuessDistance", ""));
		}
		if (StringUtils.isNotBlank(MapUtils.getString(orgMap, "RealDistance", ""))) {
			crmMap.put("travelMileage", MapUtils.getString(orgMap, "RealDistance", ""));
		}
		if (StringUtils.isNotBlank(MapUtils.getString(orgMap, "AdjustDistance", ""))) {
			crmMap.put("reviseMileage", MapUtils.getString(orgMap, "AdjustDistance", ""));
		}
		String estimatedTime = MapUtils.getString(map, "EstimatedTime");
		if (StringUtils.isNotEmpty(estimatedTime)) {
			crmMap.put("estimatedTime", estimatedTime);
		}
		return crmMap;
	}

	/**
	 * 获取外出实际里程
	 */
	@Override
	@Deprecated
	public ModelAndView getRealDistance(Map<String, Object> map) {
		// TODO Auto-generated method stub
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		try {
			UserT userT = UserThreadLocal.get();
			// 参数获取
			String orderId = MapUtils.getString(map, "orderId", "");
			if (StringUtils.isEmpty(orderId)) {
				// 丢失必要参数
				ParameterTool.writeResponse(response, SMSEnum.type17.getIndex(), SMSEnum.type17.getName());
				return null;
			}
			Map<String, Object> data = getCommonRealDistance(map);
			if(MapUtils.isNotEmpty(data)){
				ParameterTool.writeSuccessResponse(response, data);
				return null;
			}
			 else {
				ParameterTool.writeResponse(response, SMSEnum.type36.getIndex(), SMSEnum.type36.getName());
				return null;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			ParameterTool.writeErrorResponse(response);
			return null;
		}
	}

	public Map<String, Object> getCommonRealDistance(Map<String, Object> map) {
		UserT userT = UserThreadLocal.get();
		// 参数获取
		String orderId = MapUtils.getString(map, "orderId", "");
		String positionLon = MapUtils.getString(map, "positionLon");
		String positionLat = MapUtils.getString(map, "positionLat");
		WorkOrderT orderT = workOrderTDao.getWorkOrderTByOrderId(Long.valueOf(orderId));
		Map<String, Object> data = new HashMap<>();
		if (orderT.getOrderChannel() == 3) { // dcec渠道多返回出发到到达点距离 2.9.0需求
			Map<String, Object> startPointMap = workOrderFlowTDao.getWorkOrderFlowByOrderIdAndStatus(orderT.getId(),
					10);
			String startPointLon = MapUtils.getString(startPointMap, "LocLon", "0");
			String startPointLat = MapUtils.getString(startPointMap, "LocLat", "0");
			Map<String, Object> directionMap = GDRegion.direction(startPointLon, startPointLat, positionLon,
					positionLat);
			Long distance = MapUtils.getLong(directionMap, "distance", 0l);
			BigDecimal driveDistance = new BigDecimal(distance);
			BigDecimal distanceBig = driveDistance.divide(BigDecimal.valueOf(1000L), 2, RoundingMode.DOWN);
			if (null != distanceBig) {
				data.put("startEndDistance", distanceBig.toPlainString());
			} else {
				data.put("startEndDistance", 0.0);
			}

		}
		Map<String, Object> distanceMap = trackService.getWorkOrderDistance(orderT);
		log.info("工单编号:" + orderT.getOrderNo() + ",的实际里程：" + JSON.toJSONString(distanceMap));
		if (MapUtils.getBoolean(distanceMap, "result")) {

			String guessDistance = String.valueOf(orderT.getGuessDistance());
			if (orderT.getOrderChannel() == 109) {
				guessDistance = orderT.getGuessDistance().toString();
			} else {
				// 非CCEC渠道逻辑，使用服务站距离到当前点位置
				if (StringUtils.isNotEmpty(positionLon) && StringUtils.isNotEmpty(positionLat)) {
					Map<String, Object> serviceStationMap = serviceStationDao
							.getServiceStationById(orderT.getServiceStationId());
					if (MapUtils.isNotEmpty(serviceStationMap)) {
						String stationLon = MapUtils.getString(serviceStationMap, "PositionLon");
						String stationLat = MapUtils.getString(serviceStationMap, "PositionLat");
						Map<String, Object> directionMap = GDRegion.direction(stationLon, stationLat, positionLon,
								positionLat);
						Long distance = MapUtils.getLong(directionMap, "distance", 0l);
						BigDecimal driveDistance = new BigDecimal(distance);
						BigDecimal guessDistanceBig = driveDistance.divide(BigDecimal.valueOf(1000L), 2,
								RoundingMode.DOWN);
						if (guessDistanceBig.compareTo(BigDecimal.ZERO) > 0) {
							guessDistance = guessDistanceBig.toPlainString();
							workOrderTDao.updateGuessDistance(guessDistance, orderT.getId());
						}
					}
				}
			}
			data.put("guessDistance", guessDistance);

			// 处理导航距离
			// 高德轨迹点计算距离
			String distance = MapUtils.getString(distanceMap, "distance");
			BigDecimal driveDistance = new BigDecimal(distance).divide(BigDecimal.valueOf(1000L), 2,
					RoundingMode.DOWN);
			BigDecimal resultDistance = null;
			Map<String, Object> flowMap = workOrderFlowTDao.getWorkOrderFlowByUserAndStatus(orderT.getId(),
					Dictionaries.OrderStatus_10.getIndex(), userT.getId());
			if (MapUtils.isNotEmpty(flowMap)) {
				// 获取出发点经纬度
				String deportLon = MapUtils.getString(flowMap, "LocLon");
				String deportLat = MapUtils.getString(flowMap, "LocLat");
				// 计算出发点到当前点的最短里程
				Map<String, Object> directionMap = GDRegion.direction(deportLon, deportLat, positionLon,
						positionLat);
				Long shortestDistance = MapUtils.getLong(directionMap, "distance", 0L);
				BigDecimal shortestDistanceDecimal = new BigDecimal(shortestDistance)
						.divide(BigDecimal.valueOf(1000L), 2, RoundingMode.DOWN);
				log.info("导航里程:" + driveDistance + ",最短里程：" + shortestDistanceDecimal);
				// 导航里程大于最短里程，选用导航里程，反之选用最短里程
				if (driveDistance.compareTo(shortestDistanceDecimal) > 0) {
					resultDistance = driveDistance;
				} else {
					resultDistance = shortestDistanceDecimal;
				}
			}
			if (null != resultDistance) {
				data.put("driveDistance", resultDistance.toString());
			} else {
				data.put("driveDistance", 0.0);
			}
			return data;
		}
		return null;
	}
	@Override
	public void uploadRealDistance(Map<String, Object> map) {
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		try {
			Long orderId = MapUtils.getLong(map, "orderId");
			String distance = MapUtils.getString(map, "distance");
			// 判断参数是否符合规则
			if (!NumberUtils.isNatural(orderId) || !NumberUtils.isNumber(distance)) {
				ParameterTool.writeErrorResponse(response, -5);
				return;
			}
			Map<String, Object> orderMap = workOrderTDao.getOrderById(orderId);
			if (MapUtils.isNotEmpty(orderMap)) {
				// 获取已经记录的行驶里程
				String driveDistanceStr = MapUtils.getString(orderMap, "RealDistance");
				if (StringUtils.isEmpty(driveDistanceStr)) {
					driveDistanceStr = "0";
				}
				BigDecimal driveDistance = new BigDecimal(driveDistanceStr);
				// 转换前端传输里程为千米，保留2位小数
				BigDecimal addDistance = new BigDecimal(distance).divide(BigDecimal.valueOf(1000L), 2,
						RoundingMode.DOWN);
				// 累加里程
				BigDecimal realDistance = driveDistance.add(addDistance);
				// 更新实际里程
				int updateResult = workOrderTDao.updateRealDistance(realDistance.toString(), orderId);
				Map<String, Object> data = new HashMap<>(1);
				if (updateResult < 1) {
					ParameterTool.writeResponse(response, 1, "更新实际里程失败");
					return;
				}
				// 返回累加以后的行驶里程
				data.put("driveDistance", realDistance.toString());
				ParameterTool.writeSuccessResponse(response, data);
			} else {
				ParameterTool.writeErrorResponse(response, -18);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			ParameterTool.writeErrorResponse(response);
		}
	}

	@Override
	public void getRepairingOrderList(Map<String, Object> map) {
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		UserT userT = UserThreadLocal.get();
		List<String> repairingOrderList = new ArrayList<>();
		if (null != userT) {
			List<Long> orderIdList = workOrderTDao.getRepairingOrderIdListByUserId(userT.getId());
			if (CollectionUtils.isNotEmpty(orderIdList)) {
				for (Long orderId : orderIdList) {
					repairingOrderList.add(String.valueOf(orderId));
				}
			}
		}
		Map<String, Object> responseDataMap = new HashMap<>(1);
		responseDataMap.put("repairingOrderIdList", repairingOrderList);
		ParameterTool.writeSuccessResponse(response, responseDataMap);
	}

	/**
	 * 修改维修点坐标
	 * 
	 * @param map
	 * @return
	 */
	@Override
	public ModelAndView changeMaintenanceLocation(Map<String, Object> map) {
		HttpServletResponse response = (HttpServletResponse) map.get("response");
		try {
			long userId = UserThreadLocal.get() == null ? 0L : UserThreadLocal.get().getId();
			map.put("ChangePositionOperator", userId);
			map.put("ChangePositionTime", Date_Util.getNowTime());
			workOrderTDao.updateMaintenancePointByOrderNo(map);
			ParameterTool.writeSuccessResponse(response);
		} catch (Exception e) {
			// 主动回滚事务
			log.error(e.getMessage(), e);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			// TODO Auto-generated catch block
			ParameterTool.writeErrorResponse(response);
		}
		return null;
	}

}
